使用带有一个或多个符号的大小写

时间:2015-04-04 15:02:23

标签: lisp common-lisp

我仍然难以真正掌握case。我知道你提供了使用eq进行内部比较的符号,但我不确定我是否正确地做了一件事:

我已经看到我可以写,例如:

(case n
  (23 'foo)
  (42 'bar)
  (otherwise 'something-else))

我也可以写:

(case n
  ((23 42) 'foo-or-bar)
  (otherwise 'something-else))

所以我说得对,如果我指定一个列表case然后检查变量n是否匹配列表元素之一,但是如果我指定一个值,然后case直接匹配这个值?

换句话说:如果我只有一个值,是否可以使用非列表版本?

2 个答案:

答案 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完成,而不是EQEQ是指针相等,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非常有用。希望这有帮助