Defparameter and equality predicate used in case macro
Asked Answered
O

3

5

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.

Okeefe answered 22/6, 2019 at 18:40 Comment(0)
S
6

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.

Superload answered 22/6, 2019 at 18:54 Comment(3)
Thanks coredump. Makes sense. Like your IF equivalent. Leaving it to run for a little, but that seems to me like the correct answer.Okeefe
Using read-time expansion solves the problem: (let ((x snafu)) (case x (#.snafu 'yes) (t 'no))) => YESOkeefe
Only if the value is known at read-time and never changes, but yes it works.Superload
W
2

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.

Walrath answered 23/6, 2019 at 6:18 Comment(1)
Yes, indeed. Thanks Rainer.Okeefe
L
1

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

Lourielouse answered 22/6, 2019 at 20:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.