Reputation: 29
Just learning Common Lisp for a few days, but Professor had assigned an exercise for me. However, my code is not able to compile, Can anyone show me where I did wrong with my coding part?
(defun( MIN-2 a b)
(cond
((and (numberp a) (numberp b) (<= a b)) a b)
((and (numberp a) (numberp b) nil) ERROR)
)
)
Upvotes: 0
Views: 144
Reputation: 38967
Can anyone show me where I did wrong with my coding part?
(defun( MIN-2 a b)
(cond
((and (numberp a) (numberp b) (<= a b)) a b)
((and (numberp a) (numberp b) nil) ERROR)
)
)
Let me reformat your code (auto-indent + compress parentheses):
(defun (MIN-2 a b) ;; << bad syntax, as already pointed out in another answer
(cond
((and (numberp a) (numberp b) (<= a b))
a
b)
((and (numberp a) (numberp b) nil)
ERROR)))
Let's fix the syntax of defun
:
(defun MIN-2 (a b)
(cond
((and (numberp a) (numberp b) (<= a b))
a
b)
((and (numberp a) (numberp b) nil)
ERROR)))
Error (I am compiling the code under Emacs + SBCL):
Undefined variable: ERROR
Indeed, error
is a free variable here. You need to quote it.
(defun MIN-2 (a b)
(cond
((and (numberp a) (numberp b) (<= a b))
a
b)
((and (numberp a) (numberp b))
'ERROR)))
Warning:
Deleting unreachable code (ERROR is underlined).
Indeed, the condition here is a and
expression where at least one of the
expression is NIL
, which means the conjunction is always false. The case can never happen, which is why the was optimized away.
Also, the first clause's test is:
(and (numberp a) (numberp b) (<= a b))
And the clause body is a
followed by b
, which means a
is evaluated, its value discarded (it is never used), then b
is evaluated and its value is the value of the cond
expression: you always return b
when both inputs are numbers such that a <= b
.
Clearly, this is not what you should do. Other answers already covered good solutions.
I am also here to offer alternative, not necessarily homework-friendly answers:
(defun min-2 (a b)
(handler-case (if (<= a b) a b)
(error () 'error)))
(defun min-2 (a b)
(or (ignore-errors (if (<= a b) a b))
'error))
(defgeneric min-2 (a b)
(:method ((a number) (b number)) (if (<= a b) a b))
(:method (a b) 'error))
Upvotes: 1
Reputation:
I think it's worth writing functions like this in a way which makes clear what is the sanity check and what is the actual computation. So in this case the sanity check is: 'are both arguments numbers?' and the computation is the comparison of them if they are. So separate these two things rather than bundling it all into one conditional:
(defun min-2 (a b)
(if (and (numberp a) (numberp b))
;; sanity check OK, so compare them
(if (<= a b)
a
b)
'error))
Unfortunately, of course, the sanity check is not adequate:
> (min-2 1 2)
1
> (min-2 1 'a)
error
> (min-2 1 #c(1 1))
Error: In <= of (1 #C(1 1)) arguments should be of type real.
Oops: what the sanity check should be is whether the two arguments are real numbers. Fortunately, there's a predicate for that, which is realp
. So a correct version of min-2
is:
(defun min-2 (a b)
(if (and (realp a) (realp b))
;; sanity check OK, so compare them
(if (<= a b)
a
b)
'error))
Upvotes: 0
Reputation: 2521
You are using the wrong syntax for defining a function. Use defun function-name (args)
(defun MIN-2 (a b)
(cond
((and (numberp a) (numberp b) (<= a b)) a b)
((and (numberp a) (numberp b) nil) ERROR)
)
)
Upvotes: 0
Reputation: 51551
Literal translation:
(defun min-2 (a b) ; Define a Lisp function MIN-2 … takes two arguments A and B
(cond ((and (every #'numberp (list a b)) (<= a b)) a) ; if … A <= B, returns A
((and (every #'numberp (list a b)) (> a b)) b) ; if … A > B, returns B
(t 'error) ; if A or B is not a number (i. e. “else”), returns ERROR
Improvement: check for numbers just once beforehand.
(defun min-2 (a b)
(cond ((not (every #'numberp (list a b))) 'error)
((<= a b) a)
((> a b) b)))
And please indent your code and don't leave the parentheses lying around.
Upvotes: 2