0

I've been fiddling with Lisp programs for a little while and one thing that I can never seem to figure out is how to use a loop on a list inside a function. I'm trying to create a function that will take a list as the parameters while using a do... loop. I know how to do it with if statements but now I need to use a loop. Does anyone have a clue on how to do that?

(defun maximum (a_list)
  (if (= (length a_list) 1)
      (car a_list)
      (if (> (car a_list) (maximum (cdr a_list)))
          (car a_list)
          (maximum (cdr a_list))))
    (format t "~d" a_list))

Here's what I have so far on the if statements. They might not work right but at least they work.

6
  • Can you add the code for the if statements? Commented Apr 7, 2020 at 2:49
  • Does this answer your question? How to do a while loop in LISP Commented Apr 7, 2020 at 2:56
  • @rsjaffe No. I need to use a do loop. The while loop doesn't give me the right answer. Commented Apr 7, 2020 at 3:01
  • The code you show is apparently not an attempt to do it with a do...loop, but this is not a working recursive version either. The maximize function shown here always return (due to format); besides you call length at each step of recursion. Commented Apr 7, 2020 at 7:15
  • *** typo, the function returns nil (due to format returning nil) Commented Apr 7, 2020 at 7:33

3 Answers 3

2

Here another set of possibilities, in addition to those proposed in another answers.

First of all, when writing a function, one should also test for special cases, while you do not check for an empty list. So the structure of the function could be something of this type:

(defun maximum (l)
  (if (null l)
      nil        ; or give an error
      ...normal solution...))

In case of returning nil, this structure in Common Lisp is identical to the following one, given that and evaluates its arguments in sequence, and returns nil as soon as an argument is evaluated to nil, otherwise returns the value of the last argument:

(defun maximum (l)
  (and l ...normal solution...))

Here the alternative solutions.

Without loop or recursion, with predefined functions reduce (manual) and max (manual).

(defun maximum (l)
  (and l (reduce #'max l)))

With the construct dolist (manual), that iterates a variable over a list:

(defun maximum (l)
  (and l (let ((result (car l)))
           (dolist (x (cdr l) result)
             (when (> x result)
               (setf result x))))))

And finally, with a compact version of do (manual):

(defun maximum (l)
  (and l (do ((maximum-so-far (car l) (max (pop l) maximum-so-far)))
             ((null l) maximum-so-far))))
Sign up to request clarification or add additional context in comments.

Comments

1

With loop the solution is trivial:

(loop for x in '(1 2 7 4 5) maximize x)

I assume therefore that what you intend to do is to write the function with a do loop. In this case you have to traverse the list keeping track of the maximum element so far, and updating this value if you find a larger value:

(setq list '(1 2 7 4 5))

(do* ((l list (cdr l)) 
      (x (car l) (car l)) 
      (max x) ) 
     ((null l) max) 
 (if (> x max) 
   (setq max x) ))

Comments

0
(defun maximum (list)
  (let ((result)) ;; short for ((result nil))
    (dolist (x list)
      (if result
          (when (> x result)
            (setf result x))
          (setf result x)))
    result))

(dolist (x list) ... ) is like Python's [... for x in list]

It is typical imperative style to create a variable with let and setf to it to change its value.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.