Alex Pritchard
Alex Pritchard

Reputation: 4250

Simple Lisp Case statement question - problem comparing to nil

I'm trying to use a case statement to make some code more readable. It seems to work as a series of if statements, but for some reason the case statement always accepts a comparison to nil even if it is not true. Can someone clarify why this behavior occurs?

Example:

> (case 'a            
    (nil nil)         
    (otherwise 'b))   
NIL                   
> (case 'a            
    ('a 'b)           
    (otherwise nil))  
B                       

In the above example, the first instance returns nil, even though 'a clearly is not nil. Trying to do the same thing with if statements behaves as I would expect:

> (if (eq 'a nil) nil 'b)    
B                            
> (if (eq 'a 'a) 'b nil)     
B                            

I'm assuming there is some behavior about the case statement I do not understand. Any help would be appreciated.

Edit: Just to clarify, I know that 'a won't be evaluated. I just mocked up this example to create a situation in which the target of the case statement was definitely NOT nil.

I'm using xlisp-plus, but I'm going to try a real clisp install and see if it behaves differently.

Edit (one more time): Installed CLISP and it works fine there. Not really worth the trouble to investigate why xlisp is different. Thanks for the sanity check, everyone.

Upvotes: 3

Views: 4449

Answers (5)

WReach
WReach

Reputation: 18271

Each of the key specifications in a CASE may be either a list of literals or a single atom. However, CLtL says that the atom must not be NIL since it is ambiguous as to whether it is the literal NIL or an empty list. Use a list of NIL instead:

> (case 'a
    ((nil) nil)         
    (otherwise 'b))
B
> (case nil
    ((nil) nil)         
    (otherwise 'b))
NIL

Upvotes: 4

Rainer Joswig
Rainer Joswig

Reputation: 139251

Common Lisp expects for CASE the item to test to be an atom or a list of atoms. The test also is the function EQL.

(case 'a
  (a 'b)    ; EQL a
  (otherwise 'foo))

(case 'a
  ((a b c) 'foo)   ; EQL to one of a, b or c
  (otherwise 'bar))

The quoted for only works by accident. Don't use it:

; don't use this:
(case 'a
  ('a 'foo)    ; <- bad!  , EQL to QUOTE or A
  (otherwise 'bar))

Above is the same as:

; don't use this:
(case 'a
  ((quote a) 'foo)   ; <- bad! ,  EQL to QUOTE or A
  (otherwise 'bar))

Upvotes: 2

Eli Barzilay
Eli Barzilay

Reputation: 29546

The values in a case form are implicitly quoted lists of literals, so this:

(case 'a
  ((a) 'b)
  (otherwise nil))

is what you want. otherwise should work (as others have said) -- try t instead.

BTW, when you used 'a the reader reads it as (quote a) which means that it will also choose it when the value is quote, for example:

(case 'quote
  ('a 'b)
  (otherwise nil))

Upvotes: 0

lindelof
lindelof

Reputation: 35240

Same here with SBCL:

CL-USER> (case 'a
           (nil nil)
           (otherwise 'b))
B

That said, 'a is a symbol and as such can never be nil.

Upvotes: 1

Erhan Bagdemir
Erhan Bagdemir

Reputation: 5327

i think that it depends on your LISP version. I have LispWorks on Mac and my result :

CL-USER 2 : 1 > (case 'a            
    (nil nil)         
    (otherwise 'b))   
B

Upvotes: 1

Related Questions