Defparameter和等式谓词用于case宏

5

我有一些整数类型的全局变量,使用defparameter创建。我将它们用作CASE子句中的键值,以匹配在程序某个点上设置为其中一个全局变量的test-key。

据我所知,CASE宏使用EQL(http://clhs.lisp.se/Body/26_glo_s.htm#same),但是我没有找到匹配项:所有内容都被转储到otherwise子句中。下面的代码总结了让我感到困惑的问题。

  • (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

我不理解为什么在CASE子句中我没有得到YES。

3个回答

6

Case子句不会被计算,而是直接照字面意思进行匹配。以下代码:

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

等同于:

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

注意 snafu 前的引号:比较的是符号 snafu 而不是它的值。

谢谢 coredump。很有道理。喜欢你的 IF 等价物。让它运行一会儿,但那对我来说似乎是正确的答案。 - peter.cntr
1
使用读取时扩展可以解决问题:(let ((x snafu)) (case x (#.snafu 'yes) (t 'no))) => YES - peter.cntr
只有在读取时已知且永远不会更改的值才能使用,但是它确实有效。 - coredump

2

由于case是一个宏,因此可以找出它生成的代码:

最初的回答

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

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

可以看到,snafu被用作一个字面符号,而不是一个变量。最初的回答。

是的,确实。谢谢Rainer。 - peter.cntr

1

在看到@coredump的回答之前,我就开始着手处理这个问题了。这里是另一个示例:

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

; => CASE-KEYS-ARE-CONSTANTS


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接