使用带有一个或多个符号的 case
Using case with one or more symbols
我仍然无法真正掌握case
。我了解到您提供的符号在内部使用 eq
进行比较,但我不确定我是否正确理解了一件事:
我看到我会写,例如:
(case n
(23 'foo)
(42 'bar)
(otherwise 'something-else))
我也会写:
(case n
((23 42) 'foo-or-bar)
(otherwise 'something-else))
所以我是对的,如果我指定一个 case
的列表,然后检查变量 n
是否匹配 列表的一个元素 ,但是如果我指定一个值,那么case
直接匹配这个值?
换句话说:如果我只有一个值,可以使用非列表版本吗?
键在概念上是键的列表
从概念上讲,每个子句都使用一个键列表。测试密钥将与密钥列表中的每个密钥进行比较。
密钥列表 (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 与 EQL
另请注意,Common Lisp 中的大多数比较默认使用 EQL
而不是 EQ
。 EQ
是指针相等,EQL
也适用于数字和字符。
这不是直接回答你的问题,但我们可以使用 lisp 看看它在做什么。
如果您在 CLHS 页面中查找 case
,我们可以看到它是一个宏,这意味着我们可以对其进行宏扩展以查看它变成什么
那么让我们以第一个例子为例
(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 太有用了。希望这有帮助
我仍然无法真正掌握case
。我了解到您提供的符号在内部使用 eq
进行比较,但我不确定我是否正确理解了一件事:
我看到我会写,例如:
(case n
(23 'foo)
(42 'bar)
(otherwise 'something-else))
我也会写:
(case n
((23 42) 'foo-or-bar)
(otherwise 'something-else))
所以我是对的,如果我指定一个 case
的列表,然后检查变量 n
是否匹配 列表的一个元素 ,但是如果我指定一个值,那么case
直接匹配这个值?
换句话说:如果我只有一个值,可以使用非列表版本吗?
键在概念上是键的列表
从概念上讲,每个子句都使用一个键列表。测试密钥将与密钥列表中的每个密钥进行比较。
密钥列表 (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 与 EQL
另请注意,Common Lisp 中的大多数比较默认使用 EQL
而不是 EQ
。 EQ
是指针相等,EQL
也适用于数字和字符。
这不是直接回答你的问题,但我们可以使用 lisp 看看它在做什么。
如果您在 CLHS 页面中查找 case
,我们可以看到它是一个宏,这意味着我们可以对其进行宏扩展以查看它变成什么
那么让我们以第一个例子为例
(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 太有用了。希望这有帮助