Adam Hanek
Adam Hanek

Reputation: 93

Find max in lisp

I am trying to do Recursive method to find max value in list. Can anyone explain where I made the mistake on this code and how to approach it next time.

(defun f3 (i)
  (setq x (cond (> (car (I)) (cdr (car (I))))
                (f3 (cdr (I)))))
  )

(f3  '(33 11 44  2) )

also I tried this following method and didn't work:

(defun f3 (i)
  (cond ((null I )nil )
        (setq x (car (i))
              (f3(cdr (i)))
              (return-from max x)
              )

Thanks a lot for any help. I am coming from java if that helps.

Upvotes: 0

Views: 2752

Answers (3)

ignis volens
ignis volens

Reputation: 9282

Although the other answers are right: you definitely need to learn more CL syntax and you probably would not solve this problem recursively in idiomatic CL (whatever 'idiomatic CL' is), here's how to actually do it, because thinking about how to solve these problems recursively is useful.

First of all let's write a function max/2 which returns the maximum of two numbers. This is pretty easy:

(defun max/2 (a b)
  (if (> a b) a b))

Now the trick is this: assume you have some idea of what the maximum of a list of numbers is: call this guess m. Then:

  • if the list is empty, the maximum is m;
  • otherwise the list has a first element, so pick a new m which is the maximum of the first element of the list and the current m, and recurse on the rest of the list.

So, we can write this function, which I'll call max/carrying (because it 'carries' the m):

(defun max/carrying (m list)
  (if (null list)
      m
    (max/carrying (max/2 (first list) m)
                  (rest list))))

And this is now almost all we need. The trick is then to write a little shim around max/carrying which bootstraps it:

to compute the maximum of a list:

  • if the list is empty it has no maximum, and this is an error;
  • otherwise the result is max/carrying of the first element of the list and the rest of the list.

I won't write that, but it's pretty easy (to signal an error, the function you want is error).

Upvotes: 0

Kaz
Kaz

Reputation: 58627

If you're working in Common Lisp, then you do this:

(defun max-item (list)
  (loop for item in list
        maximizing item))

That's it. The maximizing item clause of loop determines the highest item value seen, and implicitly establishes that as the result value of loop when it terminates.

Note that if list is empty, then this returns nil. If you want some other behavior, you have to work that in:

(if list
  (loop for item in list
         maximizing item))
  (... handle empty here ...))

If the number of elements in the list is known to be small, below your Lisp implementation's limit on the number of arguments that can be passed to a function, you can simply apply the list to the max function:

(defun max-item (list)
  (apply #'max list))

If list is empty, then max is misused: it requires one or more arguments. An error condition will likely be signaled. If that doesn't work in your situation, you need to add code to supply the desired behavior.

If the list is expected to be large, so that this approach is to be avoided, you can use reduce, treating max as a binary function:

(defun max-item (list)
  (reduce #'max list))

Same remarks regarding empty list. These expressions are so small, many programmers will avoid writing a function and just use them directly.

Regarding recursion, you wouldn't use recursion to solve this problem in production code, only as a homework exercise for learning about recursion.

Upvotes: 2

coredump
coredump

Reputation: 38967

You are trying to compute the maximum value of a list, so please name your function maximum and your parameter list, not f3 or i. You can't name the function max without having to consider how to avoid shadowing the standard max function, so it is best for now to ignore package issues and use a different name.

There is a corner case to consider when the list is empty, as there is no meaningful value to return. You have to decide if you return nil or signal an error, for example.

The skeleton is thus:

(defun maximum (list)
  (if (null list)
      ...
      ...))

Notice how closing parentheses are never preceded by spaces (or newlines), and opening parentheses are never followed by spaces (or newlines). Please note also that indentation increases with the current depth . This is the basic rules for Lisp formatting, please try following them for other developers.

(setq x <value>)

You are assigning an unknown place x, you should instead bind a fresh variable if you want to have a temporary variable, something like:

(let ((x <value>))
  <body>)

With the above expression, x is bound to <value> inside <body> (one or more expressions), and only there.

(car (i))

Unlike in Java, parentheses are not used to group expressions for readability or to force some evaluation order, in Lisp they enclose compound forms. Here above, in a normal evaluation context (not a macro or binding), (i) means call function i, and this function is unrelated to your local variable i (just like in Java, where you can write int f = f(2) with f denoting both a variable and a method).

If you want to take the car of i, write (car i).

You seem to be using cond as some kind of if:

 (cond (<test> <then>) <else>) ;; WRONG

You can have an if as follows:

 (if <test> <then> <else>)

For example:

(if (> u v) u v) ;; evaluates to either `u` or `v`, whichever is greater

The cond syntax is a bit more complex but you don't need it yet.

You cannot return-from a block that was undeclared, you probably renamed the function to f3 without renaming that part, or copied that from somewhere else, but in any case return-from is only needed when you have a bigger function and probably a lot more side-effects. Here the computation can be written in a more functionnal way. There is an implicit return in Lisp-like languages, unlike Java, for example below the last (but also single) expression in add evaluates to the function's return value:

(defun add-3 (x) 
  (+ x 3))

Start with smaller examples and test often, fix any error the compiler or interpreter prints before trying to do more complex things. Also, have a look at the available online resources to learn more about the language: https://common-lisp.net/documentation

Upvotes: 0

Related Questions