4
votes

I have some global variables of type integer created with defparameter. I use these as keys in CASE clauses to match at test-key that was, at some point in my program, set to one of these global variables.

So far as I know, the CASE macro uses EQL (http://clhs.lisp.se/Body/26_glo_s.htm#same), but I don't get a match: all is dumped into the otherwise clause. Code below summarises what's puzzling me.

  • (defparameter snafu 123) => SNAFU
  • (let ((x snafu)) (and (eq x snafu) (eql x snafu) (equal x snafu))) => T
  • (let ((x snafu)) (case x (snafu 'yes) (t 'no))) => NO
  • (let ((x snafu)) (cond ((eql x snafu) 'yes) (t 'no))) => YES

I don't understand why I don't get YES in the CASE.

3

3 Answers

5
votes

Case clauses are not evaluated, they are taken literally. This:

(case x
  (snafu 'yes)
  (t 'no))

is equivalent to:

(if (eql x 'snafu) 'yes 'no)

Note the quote before snafu: x is compared against the symbol snafu and not its value.

2
votes

Since case is a macro, one can find out what code it generates:

* (pprint (macroexpand-1 '(case x
                            (snafu 'yes)
                            (t 'no))))

(LET ((#:G427 X))
  (DECLARE (IGNORABLE #:G427))
  (COND ((EQL #:G427 'SNAFU) NIL 'YES)
        (T NIL 'NO)))

One can see that snafu is used as a literal symbol, not a variable.

1
votes

I started working on this before I saw @coredump's answer. Here is another example:

(progn (defparameter snafu 'y) 
       (let ((x snafu)) 
           (case snafu (y 'case-keys-are-constants))))

; => CASE-KEYS-ARE-CONSTANTS