Lisp 带有一个或多个符号的用例

Lisp 带有一个或多个符号的用例,lisp,common-lisp,Lisp,Common Lisp,我仍然有一些问题需要真正理解案例。我知道您提供的符号是使用eq进行内部比较的,但我不确定是否正确获得了一件事: 我已经看到我会写作,例如: (case n (23 'foo) (42 'bar) (otherwise 'something-else)) 我还可以写: (case n ((23 42) 'foo-or-bar) (otherwise 'something-else)) 那么,如果我指定一个case的列表,然后检查变量n是否与列表中的一个元素匹配,但是如果我指

我仍然有一些问题需要真正理解
案例
。我知道您提供的符号是使用
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和其他情况的例外

请注意,
否则
(否则)
t
(t)
是例外情况。如果要匹配符号,则需要编写
(否则)

(case 'otherwise
  ((otherwise) 'the-symbol-otherwise)
  (otherwise   'the-otherwise-clause))
EQ与EQL的对比


还要注意的是,公共Lisp中的大多数比较默认使用
EQL
,而不是
EQ
EQ
是指针相等,
EQL
也适用于数字和字符。

键在概念上是键列表

从概念上讲,每个子句都使用一个键列表。测试密钥将与密钥列表中的每个密钥进行比较

键列表
(foo-bar-baz)
正是
(foo-bar-baz)

foo
被认为表示
(foo)
。它有助于缩短代码

(case x
  (foo       41)
  ((bar baz) 42)))
T和其他情况的例外

请注意,
否则
(否则)
t
(t)
是例外情况。如果要匹配符号,则需要编写
(否则)

(case 'otherwise
  ((otherwise) 'the-symbol-otherwise)
  (otherwise   'the-otherwise-clause))
EQ与EQL的对比


还要注意的是,公共Lisp中的大多数比较默认使用
EQL
,而不是
EQ
EQ
是指针等式,
EQL
也适用于数字和字符。

这不是直接回答您的问题,但我们可以使用lisp查看它在做什么

如果您在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
是一个宏。。让我们看看它是如何扩展的(我简化了它,有点像上面)

现在我们可以看到所有的逻辑

现在让我们展开下一个

(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))

宏扩展非常有用。希望这对您有所帮助

这不是直接回答您的问题,但我们可以使用lisp查看它在做什么

如果您在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
是一个宏。。让我们看看它是如何扩展的(我简化了它,有点像上面)

现在我们可以看到所有的逻辑

现在让我们展开下一个

(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))

宏扩展非常有用。希望这有帮助

你为什么不试试呢?转到lisp提示符并输入一些内容,如
(let((n3))(case n((23)'foo)(4'bar))
。但是,是的,那是正确的。你为什么不试试呢?转到lisp提示符并输入一些内容,如
(let((n3))(case n((23)'foo)(4'bar))
。但是,是的,这是正确的。好吧,那么请写出
否则
的特例总是使用括号可能是个好主意,对吗?@GoloRoden:大多数代码不使用括号来表示单个项目的键列表。好吧,那么请写出
否则
的特例总是使用括号可能是个好主意,是吗?@GoloRoden:大多数代码不使用括号来表示单个项目的键列表。这确实非常有用,感谢您的详细解释:-)哦,如果您使用的是带slime的emacs,那么将光标粘贴在开始部分,并
Ctrl+Return
这将扩展到一个新的缓冲区,然后可以展开内部宏或使用“撤消”来“取消展开”它们。macroexpand的这种探索性使用非常有启发性。(Vim with slime也会有一个键绑定,但我不知道它是什么)这确实非常有用,感谢您的详细解释:-)哦,如果您将emacs与slime一起使用,那么将光标粘贴在开始部分,并
Ctrl+Return
这将扩展到一个新的缓冲区,然后可以展开内部宏或使用“撤消”来“取消展开”它们。macroexpand的这种探索性使用非常有启发性。(带slimv的Vim也将有一个键绑定,但我不知道它是什么)