我想我明白发生了什么事。Lisp 仅将'
match 子句'(1 2 3)
和 的部分'(41 42 43)
视为键(因为它们都扩展为(Quote
... 并且从这个角度来看,第三个代码片段中的第二个'
= (QUOTE
... 是一个“重复键”(而实际上它不是)根本没有键。这只是我的语法错误)。
我认为我的主要问题是我没有正确理解编译器警告。
我不理解case
(或 sbcl)的以下行为。
在这篇SO 帖子中,R. Joswig 指出,表单的 match 子句case
不会被评估并被视为文字。因此匹配子句不应被引用。
我没有意识到这一点,引用了一个匹配条款,但忘记引用另一个。我不明白的是,为什么如果我引用一个匹配子句,编译器不会抱怨,但如果我引用两个匹配子句,编译器就会抱怨。具体来说:
> (let ((x 42))
(case x
((1 2 3) 'first-branch)
('(41 42 43) 'second-branch))) ; <= second match clause quoted
NIL
Run Code Online (Sandbox Code Playgroud)
=> 无警告。
> (let ((x 42))
(case x
('(1 2 3) 'first-branch) ; <= first match clause quoted
((41 42 43) 'second-branch)))
NIL
Run Code Online (Sandbox Code Playgroud)
=> 也没有警告。
> (let ((x 42))
(case x
('(1 2 3) 'first-branch) ; <= both quoted
('(41 42 43) 'second-branch))) ; <=
NIL
Run Code Online (Sandbox Code Playgroud)
=>样式警告:
; caught STYLE-WARNING:
; Duplicate key QUOTE in CASE form, occurring in the first clause:
; ('(1 2 3) 'FIRST-BRANCH), and the second clause:
; ('(41 42 43) 'SECOND-BRANCH).
Run Code Online (Sandbox Code Playgroud)
为什么只有当我引用两个匹配子句时编译器才会抱怨,而如果我只引用一个则编译器不会抱怨?
只是为了澄清:这里的引号符号只是另一个符号,没有任何特定含义。Common Lisp 期望表达式子句的开头case
是一个常量原子(如 )foo
或常量原子列表(如 )(foo bar baz)
。另请注意,Lisp 用作eql
比较 - 因此,在数字和字符的情况下,它会比较身份或值,但不会比较内容。
此示例表明,这quote
只是子句中的另一个符号case
:
CL-USER> (case 2
((quote foo) 'foo)
((quote bar) 'bar))
WARNING: Duplicate key QUOTE in CASE form, occurring in the first clause:
('FOO 'FOO), and the second clause:
('BAR 'BAR).
NIL
Run Code Online (Sandbox Code Playgroud)
如果我们写baz
而不是quote
我们会得到相同的警告:
CL-USER> (case 2
((baz foo) 'foo)
((baz bar) 'bar))
WARNING: Duplicate key BAZ in CASE form, occurring in the first clause:
((BAZ FOO) 'FOO), and the second clause:
((BAZ BAR) 'BAR).
NIL
Run Code Online (Sandbox Code Playgroud)