公共Lisp中的引用

公共Lisp中的引用,lisp,common-lisp,Lisp,Common Lisp,我最近开始学习lisp。我仔细阅读了书中的例子,我觉得我对每件事都理解得相当透彻,直到我在第7章中找到了以下例子: (defun quote-it (x) (list 'quote x)) 现在,我知道list将创建一个带有参数的列表,如(列表1234)将计算为列表(1234) 我还知道,quote允许我引用一个参数,就像我可以引用“一样。因此,'east与(引用east) 现在,有趣的是,上面的函数不返回列表,只引用我传递给它的任何内容。所以,如果我叫它 (引用它east)它只返回'ea

我最近开始学习lisp。我仔细阅读了书中的例子,我觉得我对每件事都理解得相当透彻,直到我在第7章中找到了以下例子:

(defun quote-it (x)
  (list 'quote x))
现在,我知道
list
将创建一个带有参数的列表,如
(列表1234)
将计算为列表
(1234)

我还知道,
quote
允许我引用一个参数,就像我可以引用
一样。因此,
'east
(引用east)

现在,有趣的是,上面的函数不返回列表,只引用我传递给它的任何内容。所以,如果我叫它

(引用它east)
它只返回
'east
,而不是
('east)

如果我这样做了,我会把函数写成

(defun quote-it (x) 
  (quote x))
因此,我不知道为什么我们在书中的示例中将命令写为
(list'quote x)

我知道我可以通过使用引号在代码和数据之间切换,比如
”(+12)
,但在这种情况下,我的目的似乎是在这里实际应用quote函数。那么,为什么要
(列出'quote x)


那么,有没有经验丰富的人能澄清这一点呢?

你被reader宏弄糊涂了。
Lisp的顶层是read/eval/print 如果你读到“(foobar),你会得到(quote(foobar))
如果您求值(quote(foo-bar)),您会得到(foo-bar)

Lisp源代码由Lisp编程中使用的一些相同的数据结构表示。这里特别重要的是列表和符号。当Lisp计算具有该表单的表单时

(quote something)
也就是说,当Lisp计算一个表单时,它是一个列表,其第一个元素是符号
quote
,然后它返回对象
something
,而不计算它。因此

现在,当计算器(或编译器,&c.)得到一个Lisp对象进行求值时,它恰好是一个列表,其第一个元素是符号
quote
。作为Lisp程序员,我们仍然需要编写代码,让Lisp阅读器读取并传递给evalutor。我们可以写长表格

(quote 2)
(quote (a b c))
在我们的源代码中,Lisp阅读器将读取它们并将它们传递给编译器,但是我们,所以我们很懒,希望避免一些键入。所以,我们可以打字

'2
'(a b c)
相反。编译器最终得到完全相同的输入;一种列表,其第一个元素是符号
quote
,第二个值是
2
(a b c)

现在我们可以谈谈你的代码了。形式

(list 'quote x)
返回一个列表,其第一个元素是符号
quote
,第二个元素是变量
x
的值。可以打印为

但是请注意,您得到的是一个符号,您得到的是符号
x
。您不会得到第一个元素是符号
quote
,第二个元素是
的列表。当您使用
将其与其他值一起引用时,您将看到问题:

(quote-it 2)
;=> x
你仍然可以拿回一个符号,因为

(defun quote-it (x) 
  (quote x))         ; or 'x
获取一个参数,将其绑定到词法变量
x
,然后返回
(引号x)
的值。
(引号x)
的值是多少?如前所述,当计算器(或编译器,&c.)获取符号
quote
something
的列表时,该值是文本
something
。由于
quote it
的主体是符号
quote
和符号
x
的列表,因此
quote it
主体的值是符号
x

Lisp有列表,如:(mary扔了球)

有些列表描述计算,如:(*pi(+r))

第一个列表是数据,第二个是一个表达式,适合于评估者仔细研究

但我们需要一种在表达式中包含数据的方法。几十年前,一个特殊的操作符被引入来实现这一点,比如:(数数名词(引用玛丽扔的球)))

随着时间的推移,开发人员已经厌倦了打字(引用…),所以他们发明了一种简写符号:(计算名词(玛丽扔球))

如今,速记是在读取时实现的,因为字符是从文件中或从终端读取的。这是用一种叫做“读取器宏”的工具来完成的。这个名字让大多数初学者感到困惑,因为语言中还有一种叫做“宏”的工具,它实际上与读取文件几乎没有任何关系。它们通常用于添加一点语法糖。如本报价示例所示。读取文件(或终端)流后,所有内容都只是一个列表

您会注意到,如果在lisp提示符中输入:(引用bob),您将返回:“bob”。打印机非常清楚(引用bob)具有速记形式的约定。如果您决定编写自己的阅读器宏,您可能需要教打印机如何操作


宏,作为v.s.reader宏,允许您介绍自己的特殊运算符。这使您可以在代码中嵌入自定义的特定于域的语言。所以,排序宏允许您扩展语义,读卡器宏允许您扩展语法。宏会影响编译器和计算器的行为。

示例:如果要构造一个包含符号
foo
和变量号的列表:

  • 我们有一个号码
  • 我们想列一个清单
    (foo)
现在我们为它编写一个函数:

(defun foo-it (n)
  (list 'foo n))
显然

(defun foo-it-1 (n)
  (foo n))
不行。它将调用
n
上的函数
FOO
,而不是构造一个列表

(defun foo-it-2 (n)
  '(foo n))
由于列表
(foo n)
未按原样计算和返回,上述操作也不起作用

现在Lisp有了反引号语法:

(defun foo-it-3 (n)
  `(foo ,n))
以上方法将起作用。逗号标记符号
n
将被计算

为了你的问题
(defun foo-it (n)
  (list 'foo n))
(defun foo-it-1 (n)
  (foo n))
(defun foo-it-2 (n)
  '(foo n))
(defun foo-it-3 (n)
  `(foo ,n))
(list 'foo n)  ->   (list 'quote n)
`(foo ,n)    ->     `(quote ,n)
CL-USER 14 > (progn
               (write (list 'foo 3) :pretty nil)
               (terpri)
               (write (list 'foo 3) :pretty t)
               (values))
(FOO 3)
(FOO 3)

CL-USER 15 > (progn
               (write (list 'quote 3) :pretty nil)
               (terpri)
               (write (list 'quote 3) :pretty t)
               (values))
(QUOTE 3)
'3