我仍然难以真正掌握case
。我知道你提供了使用eq
进行内部比较的符号,但我不确定我是否正确地做了一件事:
我已经看到我可以写,例如:
(case n
(23 'foo)
(42 'bar)
(otherwise 'something-else))
我也可以写:
(case n
((23 42) 'foo-or-bar)
(otherwise 'something-else))
所以我说得对,如果我指定一个列表case
然后检查变量n
是否匹配列表元素之一,但是如果我指定一个值,然后case
直接匹配这个值?
换句话说:如果我只有一个值,是否可以使用非列表版本?
答案 0 :(得分:4)
键是概念上的键列表
从概念上讲,每个子句都使用一个键列表。测试密钥将与密钥列表中的每个密钥进行比较。
密钥列表(foo bar baz)
正好是(foo bar baz)
。
密钥foo
被认为代表(foo)
。它有助于缩短代码。
(case x
(foo 41)
((bar baz) 42)))
T和OTHERWISE例外
请注意,otherwise
和(otherwise)
,t
和(t)
是例外情况。如果要匹配符号,则需要编写(otherwise)
:
(case 'otherwise
((otherwise) 'the-symbol-otherwise)
(otherwise 'the-otherwise-clause))
EQ vs. EQL
另请注意,Common Lisp中的大多数比较默认使用EQL
完成,而不是EQ
。 EQ
是指针相等,EQL
也适用于数字和字符。
答案 1 :(得分:2)
这不是直接回答你的问题,但我们可以使用lisp看看它在做什么。
如果您查看case
的CLHS页面,我们可以看到它是一个宏,这意味着我们可以宏观扩展它以查看它变成了什么
让我们来看第一个例子
(case n
(23 'foo)
(42 'bar)
(otherwise 'something-else))
这扩展为
(LET ((#:G1246 N))
(COND ((EQL #:G1246 '23) NIL 'FOO)
((EQL #:G1246 '42) NIL 'BAR)
(T NIL 'SOMETHING-ELSE)))
#:G1246
是一个gensym,我们可以将其视为lisp保证唯一的符号。我现在要将其重命名为tmp
(let ((tmp n))
(cond ((eql tmp '23) nil 'foo)
((eql tmp '42) nil 'bar)
(t nil 'something-else)))
同样cond
是一个宏..让我们看看它是如何扩展的(我已经简化了上面的内容)
(let ((tmp n))
(if (eql tmp '23)
'foo
(if (eql tmp '42)
'bar
'something-else)))
现在我们可以看到所有的逻辑
现在让我们展开下一个
(case n
((23 42) 'foo-or-bar)
(otherwise 'something-else))
变为
(let ((tmp n))
(if (or (eql tmp '23) (eql tmp '42))
'foo-or-bar
'something-else))
Macroexpand非常有用。希望这有帮助