hello
hello

Reputation: 29

how to take care mutiply condition check in Common lisp?

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?This is the question

(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

Answers (4)

coredump
coredump

Reputation: 38967

Why your code fails

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.

Alternatives

I am also here to offer alternative, not necessarily homework-friendly answers:

Catch exceptions

(defun min-2 (a b)
  (handler-case (if (<= a b) a b)
    (error () 'error)))

Catch exceptions (bis)

(defun min-2 (a b)
  (or (ignore-errors (if (<= a b) a b))
      'error))

Use generic functions

(defgeneric min-2 (a b)
  (:method ((a number) (b number)) (if (<= a b) a b))
  (:method (a b) 'error))

Upvotes: 1

user5920214
user5920214

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

Andreas
Andreas

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

Svante
Svante

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

Related Questions