lisp quote
如何在内部工作?
例如:
(quote (+ 1 (* 1 2)) )
似乎等同于
(list '+ 1 (list '* 1 2))
这意味着它是一种递归地象征Head值的方法。这个功能是内置的吗?
如果你不相信我,请运行(equal (quote (+ 1 (* 1 2))) (list '+ 1 (list '* 1 2)))
。
答案 0 :(得分:3)
如何运作?
quote
实现起来非常简单。它什么都没做。 quote
特殊运算符只是返回包含的对象。而已。没有评价。对象不会以任何方式改变。
引用表格的评估
可能是从1960年开始阅读麦卡锡的好时机:
Recursive Functions of Symbolic Expressions and Their Computation by Machine, Part I
第16/17页用eval
解释评估。这里:
eq [car [e]; QUOTE] → cadr [e];
或以s表达式表示法:
(cond
...
((eq (car e) 'quote)
(cadr e))
...)
上面的代码实现了QUOTE
的评估规则:如果表达式是列表而列表的第一个元素是符号QUOTE
,则返回列表的第二个元素。
引用列表与LIST
(equal (quote (+ 1 (* 1 2)))
(list '+ 1 (list '* 1 2)))
结果是T
。这意味着两个结果列表在结构上都是等价的。
(eq (quote (+ 1 (* 1 2)))
(list '+ 1 (list '* 1 2)))
结果是NIL
。这意味着链表的第一个缺点单元不是相同的对象。 EQ
测试我们是否真的拥有相同的cons单元对象。
QUOTE
返回一个文字数据对象。修改此对象的后果未定义。所以,不要这样做。
LIST
每次调用时都会返回一个新的consed列表。新的新列表不会与任何先前分配的列表共享任何利益单元格。
所以主要区别在于QUOTE
是一个内置运算符,它返回文字和未评估的数据。而LIST
是一个函数,它创建一个新的,新的列表,其参数为内容。
查看有关EQ
和EQUAL
的效果:
CL-USER 6 >
(flet ((foo () (quote (+ 1 (* 1 2))))
(bar () (list '+ 1 (list '* 1 2))))
(list (list :eq-foo-foo (eq (foo) (foo)))
(list :eq-foo-bar (eq (foo) (bar)))
(list :eq-bar-bar (eq (foo) (bar)))
(list :equal-foo-foo (equal (foo) (foo)))
(list :equal-foo-bar (equal (foo) (bar)))
(list :equal-bar-bar (equal (foo) (bar)))))
((:EQ-FOO-FOO T)
(:EQ-FOO-BAR NIL)
(:EQ-BAR-BAR NIL)
(:EQUAL-FOO-FOO T)
(:EQUAL-FOO-BAR T)
(:EQUAL-BAR-BAR T))
是引用功能吗?
quote
不能是一个函数,因为它返回未包含的封闭数据。因此,这是一个特殊的评估规则。
如果quote
是一个函数,那么它的参数就会被评估。但这正是 NOT quote
应该做的事情。
为什么Lisp需要QUOTE
?
Lisp通常使用s表达式来编写Lisp代码。所以s表达式既有表示数据的目的,也有用它来编写程序。在Lisp程序中,列表用于函数调用,宏表单和特殊表单。符号用作变量:
(+ n 42)
此处(+ n 42)
是一个列表,n
是一个符号。但我们也希望在我们的程序中使用列表作为数据,并且我们希望使用符号作为数据。因此我们必须引用它们,以便Lisp不会将它们视为程序,而是作为数据:
(append '(+ n) '(42)) evaluates to (+ n 42)
因此,在Lisp程序中,列表和变量默认是语言元素的一部分,例如函数调用和变量。如果我们想使用列表和符号作为文字数据,我们必须引用它们,以防止评估者将它们视为要评估的Lisp代码。
答案 1 :(得分:2)
quote
只会使其论点无法评估。但是什么是无价值的论点?
当定义Lisp程序时,它可以从文本源读取为s表达式,也可以直接用s表达式构造。宏将是生成s表达式的示例。无论哪种方式,都有一个数据结构,包括(大部分)代表程序的符号和conses。
大多数Lisp表达式将调用评估和编译机制来将此数据结构解释为程序中的术语。 quote
被特别处理,传递这些未解释的符号并将其作为参数。简而言之,quote
几乎没有任何作用 - 它返回的值已经存在并且只是通过。
您可以使用eq
来测试传递和新构造之间的区别,以测试引用的返回值的标识:
(defun f () '(1 2))
(defun g () (list 1 2))
(eq (f) (f)) => T
(eq (g) (g)) => NIL
如您所见,quote
每次都会返回相同的词。