Reputation: 3611
I'm new to lisp
and trying to write a recursive function that returns minimum number from a list. It also wants to detect atom. The following code returns error:
(defun minFromList (l)
(cond ((null l) nil) ; Causes error shown below
; (cond ((null l) ) ; Causes the same error
; (cond ((null l) 0) ; It causes always 0 to be the final return val.
((numberp l) l)
((numberp (car l)) (min (car l) (minFromList(cdr l))))
((listp (car l)) (min (minFromList (car l)) (minFromList (cdr l))))
(t nil) ; if all condition doesn't hold just return nil.
)
)
Error:
*** - MIN: NIL is not a real number
Apparently the problem lies in where it returns nil/0 when the given list is null. What's possible workarounds? Thank you.
Environment) Ubuntu 11.10, clisp 2.49
Update) Although I already picked up this as the answer, I welcome if there are other ways especially w/o making new functions if any.
Here's the simplest code I made inspired by the chosen answer.
(defun minNum (a b)
(cond ((null a) b)
((null b) a)
(t (min a b)))
)
Upvotes: 1
Views: 3106
Reputation: 14065
The simplest approach I can think of is to wrap an application of min
.
(defun min-or-nil (num-list)
(when num-list (apply #'min num-list)))
Upvotes: 1
Reputation: 3060
Apparently you get an error message because you try to use the result of your function as a number, and said result is nil
when the function is called with an empty list as argument, so the evaluation that tries to use the result fails. This is not a Common Lisp problem - you have to decide what to return when the argument is empty. Maybe 0 is a good value, maybe some approximation of minus infinity - only you (or whoever uses your function) can tell.
As for getting the the minimum (or the sum or any other 'reduction') of a list, this is a pattern already handled by the reduce
Common Lisp standard function. So min-from-list
could look something like:
CL-USER> (defun min-from-list (list &optional (default 0))
(reduce #'min list :initial-value default))
MIN-FROM-LIST
CL-USER> (min-from-list '(1 2 -3))
-3
CL-USER> (min-from-list '(1 2 -3) -7)
-7
CL-USER> (min-from-list '())
0
CL-USER> (min-from-list '() -3)
-3
(the user can specify what the minimum of an empty list is - if none specified, it's 0).
Upvotes: 4
Reputation: 15759
When comparing two numbers, you need to deal with the nil
case in some way. This is easy to do. Define your own version of min
that satisfies
(min2 nil <x>) = <x>
(min2 <x> nil) = <x>
(min2 <x> <y>) = (min <x> <y>) if <x>, <y> non-null
and use that.
Upvotes: 2