为什么在大小写/案例中不能匹配nil?

时间:2019-01-10 11:49:02

标签: common-lisp sbcl

以下形式

(let ((foo nil))
  (ecase foo
    (:bar 1)
    (:baz 2)
    (nil 3)))

抛出错误NIL fell through ECASE expression。解决方法似乎是将nil大小写用括号括起来,如下所示:

(let ((foo nil))
  (ecase foo
    (:bar 1)
    (:baz 2)
    ((nil) 3))) ;; => 3

但是为什么第一个示例不起作用?展开的nil大小写是否有特殊含义?

1 个答案:

答案 0 :(得分:8)

case中的每个子句可以匹配单个项目或项目列表,例如你可以这样写:

(ecase foo
  (:bar 1) ;; match a specific symbol
  ((:baz :quux) 2)) ;; match either of these symbols

NIL也是Lisp中的空列表,在case中用作测试时,这就是它的处理方式,因此它永远不会匹配任何内容。同样,TOTHERWISE用于指定默认大小写,因此您不能将它们作为单个项目进行匹配。要匹配其中任何一个,您需要将它们放在列表中。

从技术上讲,specification谈到子句中的键:

  

---对象列表的指示符。在这种情况下,符号totherwise可能不用作键指示符。要将这些符号本身称为键,必须分别使用指示符(t)(otherwise)

list designator的定义是:

  

一个对象列表的指示符;也就是说,一个对象表示一个列表,并且是下列对象之一:非零原子(表示元素为该非零原子的单例列表)或适当的列表(表示自身)。

请注意,将单个原子视为单例列表的情况为“非零原子”。这允许NIL进入第二种情况,其中一个适当的列表表示了自己。否则,将无法为空列表创建列表指示符,因为NIL将表示(NIL)

您可能会争辩说,CASE中的键列表为空没有太大意义,因为它永远不会匹配任何内容,整个子句可以省略。这种退化的情况是为了自动代码生成(例如,其他扩展为CASE的宏)的好处,因为它们可能会产生空列表,并且应该与其他列表保持一致。对于他们来说,使子句的生成以是否有任何键为条件更加困难。