Get the maximum value of a list with three numbers

1.9k Views Asked by At

I'm learning Lisp now, and I'm trying to do an exercise that asks me to get the maximum value of a list, the syntax is totally different from most programming languages I've learned, so I'm having some difficulties.

My code:

 (defun test(y)
     (cond
          ((and (first y) (> (second y)) (> (third y))) 
        (format t "numero maximo ~d" (first y))
          ((and (second y) (> (first y)) (> (third y))) 
        (t (format t "numero maximo ~d" (second y))
          ((and (third y) (> (second y)) (> (first y))) 
        (t (format t "numero maximo ~d" (third y))
    ))

I'm receiving this error: incomplete s-expression in region

2

There are 2 best solutions below

0
coredump On BEST ANSWER

Your code is too complex, it tries to take elements from a list, compare them, and print something. Like in other languages, use smaller functions and, particularly with a new language, test often in order to avoid having to debug something too large.

Your code, automatically indented with Emacs, looks as follows:

(defun test(y)
  (cond
    ((and (first y) (> (second y)) (> (third y)))
     (format t "numero maximo ~d" (first y))
     ((and (second y) (> (first y)) (> (third y)))
      (t (format t "numero maximo ~d" (second y))
         ((and (third y) (> (second y)) (> (first y)))
          (t (format t "numero maximo ~d" (third y))
             ))

And the editor complains about unbalanced parentheses:

  • In (> (second y)), the > function is given only one argument
  • All your cond clauses are in fact nested inside the first clause. Using an editor that highlights matching parentheses helps a lot here. The syntax should be:

    (cond
      (test-1 ...)
      (test-2 ...)
      (t ...))
    

    If your test involves calling predicates, then it looks like:

    (cond
      ((and (f1 ...) (f2 ...)) ;; <-- test
       ... ;; <-- code
      ) ;; end of first clause
    ) ;; end of cond
    

    But note that you do not need to put comments for closing delimiters, the indentation and the automatic highlighting of parentheses should help you avoid mistakes.

Let's try a rewrite.

First of all, you can write a function that just compares numbers, not thinking about lists or formatting; here is a very straightforward max-of-3 implementation (without cheating and calling the built-in max function):

(defun max-of-3 (x y z)
  (if (> x y)
      (if (> x z) x z)
      (if (> y z) y z)))

Evaluate the function, and test it on multiple inputs, for example in the REPL:

CL-USER> (max-of-3 0 2 1)
2
....

Then, you can build up the other function, for your list:

(defun test (list)
   (format t 
           "numero maximo ~d"
           (max-of-3 (first list)
                     (second list)
                     (third list))))

If you need to do more error checking ahead of time, like checking that the lists is well-formed, you should probably define other auxiliary functions.

0
Indinfer On

If I understood the question and answer, I might be able to provide a solution or two that returns the max, regardless of the length of the list. So, these solutions are not limited to a list of three.

This illustrates a way to test where "max-lst" is the Lisp function under test:

(defconstant test-case 
  (list 1 2 0 8 7 6 9 4 5))

(defun run-test ()
  (max-lst test-case))

Solution 1

This solution uses recursion. If you like loops better, Lisp has several loops. The Lisp function "max" is not used:

(defun max-lst (lst-in)
  (cond ((null (second lst-in))
         (first lst-in))

        ((> (first lst-in) (second lst-in))
         (max-lst
          (list* (first lst-in) (rest (rest lst-in)))))

        (t
         (max-lst
          (list* (rest lst-in))))))
         

Solution 2

If you have no objection to using the Lisp function "max," here is a solution using max.

Note that max is not limited to two arguments.

(max 5 6 4 7 3)

will return 7.

In this solution, the function "max" is passed to the function "reduce" as an argument. The "reduce" function takes a function and a list as arguments. The function is applied to each adjacent pair of arguments and returns the result. If you want the sum, you can pass the + argument.

(defun max-lst-using-max (lst-in)
  (reduce #'max lst-in)) 

Alas, I fear that I provide these solutions too late to be pertinent to the original poster. But maybe someone else will have a similar question. So, perhaps this could help, after all.