Lisp 案件质询

Lisp 案件质询,lisp,common-lisp,Lisp,Common Lisp,我试图为cond和case创建一个示例,并提出了一个关于嘶嘶嗡嗡声问题的简单实现(有关详细信息,请参阅) 我最初的版本是: (defun is-fizz-buzz (n) (cond ((and (zerop (mod n 3)) (zerop (mod n 5))) 'fizz-buzz) ((zerop (mod n 3)) 'fizz) ((zerop (mod n 5)) 'buzz) (t n))) (defun fizz-buzz

我试图为
cond
case
创建一个示例,并提出了一个关于嘶嘶嗡嗡声问题的简单实现(有关详细信息,请参阅)

我最初的版本是:

(defun is-fizz-buzz (n)
  (cond ((and (zerop (mod n 3)) (zerop (mod n 5))) 'fizz-buzz)
        ((zerop (mod n 3)) 'fizz)
        ((zerop (mod n 5)) 'buzz)
        (t n)))

(defun fizz-buzz (n)
  (princ (case (is-fizz-buzz n)
               ('fizz "Fizz!")
               ('buzz "Buzz!")
               ('fizz-buzz "Fizz-Buzz!")
               (otherwise n))))
现在,他向我指出我的
案例
是错误的。我很惊讶,因为它已经发挥了应有的作用,但由于他比我对Lisp的经验更丰富,他很可能是对的(事实上,他是对的)

我试着去阅读和理解,但现在留给我的问题多于答案。因为我不想用140个字符来讨论问题,而且它可能对其他Lisp初学者有所帮助,所以我想在这里发表我的问题

基本上,
case
的语法描述如下

case keyform {normal-clause}* [otherwise-clause] => result*
keyform
很简单:它是一个经过评估以获得正在测试的密钥的表单。当然

(is-fizz-buzz n)
是一个窗体,它返回一个符号,因此一切看起来都很好。此外,正如我从Lisp之地学到的,
case
在内部与
eq
一起工作,并且由于
eq
用于比较符号,这也应该很好

现在,
normal子句
:定义为

(keys form*)
form*
同样很简单,它只是一些表单,基本上带有一个隐式的
progn
。对于
,它告诉我这是对象列表的指示符。呸。我的问题从这里开始

告诉我指示符是:

表示另一个对象的对象

嗯。
case
正在使用
eq
,我希望我需要在这里给出一个符号。为什么
keys
是对象列表的指示符,而不是单个对象的指示符?我可以在一个分支中比较多个符号吗?我想这里的问题归结为没有真正理解
指示符的含义,但也许有人可以帮助我,把我推向正确的方向。您如何解释Lisp中的指示符是什么

然后,我开始玩弄代码,我注意到如果我删除
字符,事情仍然有效。代码

(defun fizz-buzz (n)
  (princ (case (is-fizz-buzz n)
               (fizz "Fizz!")
               (buzz "Buzz!")
               (fizz-buzz "Fizz-Buzz!")
               (otherwise n))))
生成与上述代码完全相同的结果。为什么会这样?我甚至不希望它是可执行的,因为
(fizz“fizz!”)
对我来说就像是对
fizz
的函数调用,它是不存在的。为什么这样做有效

最后一个问题是,我什么时候跑步

(case 'quote ('foo 1) ('bar 2))
它返回
1
(这似乎不符合逻辑,我希望
nil
)。如果我把这个改成

(case 'quote ('foo 1) ('bar 2) (otherwise 3))
它仍然返回
1
,而不是我现在所期望的
3
。从文档中我不明白为什么我的otherwise子句显然没有它应该做的事情


这两个案例为什么会有这样的表现?

好吧,我能够自己解决一些问题,主要是通过阅读。这向我解释了为什么我的otherwise子句不起作用,也解释了为什么

(case 'quote ('foo 1) ('bar 2))
正在以目前的方式进行评估。所以我想我的
嘶嘶嗡嗡
功能至少应该是:

(defun fizz-buzz (n)
  (princ (case (is-fizz-buzz n)
               (fizz "Fizz!")
               (buzz "Buzz!")
               (fizz-buzz "Fizz-Buzz!")
               (otherwise n))))
(defun fizz-buzz (n)
  (princ (case (is-fizz-buzz n)
               ((fizz) "Fizz!")
               ((buzz) "Buzz!")
               ((fizz-buzz) "Fizz-Buzz!")
               (otherwise n))))
更新 好的,在多次重读上述问题和答案之后,我想我终于明白了对象列表的含义,因此我的代码应该是:

(defun fizz-buzz (n)
  (princ (case (is-fizz-buzz n)
               (fizz "Fizz!")
               (buzz "Buzz!")
               (fizz-buzz "Fizz-Buzz!")
               (otherwise n))))
(defun fizz-buzz (n)
  (princ (case (is-fizz-buzz n)
               ((fizz) "Fizz!")
               ((buzz) "Buzz!")
               ((fizz-buzz) "Fizz-Buzz!")
               (otherwise n))))

CASE
使用
EQL
而不是
EQ
<代码>EQL
在大多数情况下是默认比较。因此,case适用于标识、数字和字符

不评估键形式。因此,引用对象是没有意义的。引用意味着停止评估。但是没有评估->没有报价

keyform可以是单个项目,也可以是项目列表

(case foo
  (bar 'it-is-bar)
  ((1 2) 'one-or-two)
  (1     'one))
  ((apple banana orange) 'either-apple-banana-or-orange)))
这也意味着左边的一个是常量,没有变量<上面的code>bar是符号
bar
,而不是变量
bar

问题:

 (case 'quote
   ('foo 'foo-or-quote))
因为确实如此

 (case 'quote
   ((quote foo) 'foo-or-quote))
对于
,它告诉我这是 物体。呸。我的问题从这里开始

告诉我指示符是:

表示另一个对象的对象

嗯。
case
正在使用
eq
,我本以为我需要 在这里给一个符号。为什么
keys
列表的指示符 一个物体,而不是一个?我可以要多个符号吗 可以在一个分支中与之相比吗?我想问题来了 实际上,我们并不理解
指示符的含义,但是
也许有人能帮我,把我推向正确的方向。怎么
你能解释一下Lisp中的指示符是什么吗

我最初将此作为评论发布,但我认为这可能是一个足够的答案,如果这是问题的核心问题,那么我将添加它作为答案

您需要的文本在HyperSpec中。注释

由“指示符”表示的对象的特定性质 或者可以在术语表条目中找到“a的指示符” 用于“指示符”

列表指示符的术语表条目是您所需要的:

n。对象列表的指示符;就是, 一个表示一个列表的对象,它是一个非零原子
(表示元素为非零原子的单态列表)或适当的列表(表示自身)

因此,符号
fizz
(非零原子)和列表
(fizz)
都表示列表
(fizz)
,列表
(引用fizz)
(通常缩写为
'fizz
)表示自身,等等

一旦您了解了列表指示符,就可以在您自己的代码中使用它们。只需记录您接受一个列表指示符,然后使用
(if(listp x)x(list x))
进行转换,就可以了。它非常有用,而且你会发现它比你预期的有更多的用途。例如,我前几天刚用过它。

谢谢你的解释