Common lisp 为什么在case/ecase中不能匹配nil?

Common lisp 为什么在case/ecase中不能匹配nil?,common-lisp,sbcl,Common Lisp,Sbcl,以下表格 (let ((foo nil)) (ecase foo (:bar 1) (:baz 2) (nil 3))) 通过ECASE表达式抛出错误NIL。解决方法似乎是用括号将nil大小写括起来,如下所示: (let ((foo nil)) (ecase foo (:bar 1) (:baz 2) ((nil) 3))) ;; => 3 但是为什么第一个例子不起作用呢?未包装的nil大小写是否有特殊含义?大小写中的每个子句可以

以下表格

(let ((foo nil))
  (ecase foo
    (:bar 1)
    (:baz 2)
    (nil 3)))
通过ECASE表达式抛出错误
NIL。解决方法似乎是用括号将
nil
大小写括起来,如下所示:

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

但是为什么第一个例子不起作用呢?未包装的
nil
大小写是否有特殊含义?

大小写中的每个子句可以与单个项目或项目列表匹配,例如,您可以编写:

(ecase foo
  (:bar 1) ;; match a specific symbol
  ((:baz :quux) 2)) ;; match either of these symbols
NIL
也是Lisp中的空列表,当它在
case
中用作测试时,这就是它的处理方式,因此它从不匹配任何内容。类似地,
T
否则
用于指定默认情况,因此不能将它们作为单个项目进行匹配。要匹配其中任何一个,您需要将它们放在列表中

更严格地说,在一个条款中提到了关于键的内容:

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

a的定义是:

对象列表的指示符;也就是说,一个表示列表的对象是:一个非nil原子(表示元素为该非nil原子的单态列表)或一个适当的列表(表示自身)

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


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

您也可以使用
'nil
@Gwang JinKim,但是,您也可以匹配
quote
,因为
'nil
(quote nil)
的读取器语法,在案例的上下文中,这意味着匹配
quote
nil
@coredump谢谢-真-我试过:
(let((foo'quote))(案例foo(bar 1)(baz 2)(quote'upps)('nil 3));;返回UPPS
,因此对于
nil
的情况,只有
(nil)
才能正确匹配。@Gwang JinKim:不计算案例项,因此引用它们毫无意义。不要在案例中使用引号。这完全有道理。谢谢你的解释!