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