何时在Lisp中使用'(或引用)?
在介绍Lisp书的主要部分之后,我仍然无法理解特殊运算符(quote)
(或等价'
函数)的作用,但这已经遍布我所见过的Lisp代码。
它有什么作用?
简短回答绕过默认评估规则,不评估表达式(符号或s-exp),将其按照键入的顺序传递给函数。
长答案:默认评估规则
当一个普通的函数被调用时,所有传递给它的参数都会被计算。 这意味着你可以写这个:
(* (+ a 2)
3)
依次通过评估a
和2来评估(+ a 2)
。在当前变量绑定集中查找符号a
的值,然后替换。 说a
目前绑定的值3:
(let ((a 3))
(* (+ a 2)
3))
我们会得到(+ 3 2)
,然后在3和2上调用+,得到5.我们的原始形式现在是(* 5 3)
产生15。
解释quote
已经!
好的。 从上面可以看出,所有参数的函数进行评估,因此,如果您想通过符号a
,而不是它的价值,你不希望对其进行评估。 Lisp符号可以将它们的值都加倍,而在其他语言中可能会使用字符串的标记(如密钥散列表)。
这就是quote
地方。假设你想从一个Python应用程序绘制资源分配,而是在Lisp中进行绘图。 让你的Python应用程序做这样的事情:
print "'("
while allocating:
if random.random() > 0.5:
print "(allocate %d)" random.randint(0, 20)
else:
print "(free %d)" % random.randint(0, 20)
...
print ")"
给你输出看起来像这样(稍微满意):
'((allocate 3)
(allocate 7)
(free 14)
(allocate 19)
...)
请记住我所说的quote
默认规则不适用的quote
(“tick”)? 好。 否则会发生的是allocate
和free
的价值被抬头,我们不希望这样。 在我们的Lisp中,我们希望做到:
(dolist (entry allocation-log)
(case (first entry)
(allocate (plot-allocation (second entry)))
(free (plot-free (second entry)))))
对于上面给出的数据,下面的函数调用序列将会被创建:
(plot-allocation 3)
(plot-allocation 7)
(plot-free 14)
(plot-allocation 19)
但是什么关于list
?
那么,有时候你确实想评估论证。 假设你有一个漂亮的函数来处理一个数字和一个字符串,并返回结果列表。 让我们做一个错误的开始:
(defun mess-with (number string)
'(value-of-number (1+ number) something-with-string (length string)))
Lisp> (mess-with 20 "foo")
(VALUE-OF-NUMBER (1+ NUMBER) SOMETHING-WITH-STRING (LENGTH STRING))
嘿! 这不是我们想要的。 我们希望有选择地评估一些参数,并将其他参数作为符号。 试试#2!
(defun mess-with (number string)
(list 'value-of-number (1+ number) 'something-with-string (length string)))
Lisp> (mess-with 20 "foo")
(VALUE-OF-NUMBER 21 SOMETHING-WITH-STRING 3)
不只是quote
,但backquote
quote
好多了! 可以肯定的是,这种模式在(大部分)宏中非常常见,有特殊的语法来完成这一点。 反引号:
(defun mess-with (number string)
`(value-of-number ,(1+ number) something-with-string ,(length string)))
这就像使用quote
,但可以通过用逗号前缀来显式评估一些参数。 结果等同于使用list
,但是如果从宏生成代码,则通常只需评估返回的代码的小部分,因此反引用更适合。 对于较短的列表, list
可以更易读。
嘿,你忘了关于quote
!
那么,这使我们在哪里? 哦,对, quote
实际上是做什么的? 它只是简单地返回未评估的参数! 请记住我在开始时对常规功能所说的话吗? 结果发现一些操作符/函数不需要评估它们的参数。 比如IF - 如果没有被采用,你不希望else分支被评估,对吧? 所谓的特殊操作符和宏一起就是这样工作的。 特殊的操作符也是语言的“公理” - 最少的一组规则 - 您可以通过不同的方式将它们结合在一起来实现Lisp的其余部分。
回到quote
,但:
Lisp> (quote spiffy-symbol)
SPIFFY-SYMBOL
Lisp> 'spiffy-symbol ; ' is just a shorthand ("reader macro"), as shown above
SPIFFY-SYMBOL
比较(在Steel-Bank Common Lisp上):
Lisp> spiffy-symbol
debugger invoked on a UNBOUND-VARIABLE in thread #<THREAD "initial thread" RUNNING {A69F6A9}>:
The variable SPIFFY-SYMBOL is unbound.
Type HELP for debugger help, or (SB-EXT:QUIT) to exit from SBCL.
restarts (invokable by number or by possibly-abbreviated name):
0: [ABORT] Exit debugger, returning to top level.
(SB-INT:SIMPLE-EVAL-IN-LEXENV SPIFFY-SYMBOL #<NULL-LEXENV>)
0]
因为当前范围内没有spiffy-symbol
!
加起来
quote
, backquote
(用逗号)和list
是用来创建列表的一些工具,它们不仅是值列表,而且正如您看到的,可以用作轻量级(无需定义struct
)数据结构!
如果您想了解更多信息,我推荐Peter Seibel的Practical Common Lisp一本书来学习Lisp的实用方法,如果您已经开始编程。 最后在你的Lisp旅程中,你也会开始使用软件包。 Ron Garret的Common Lisp软件包的白痴指南会给你很好的解释。
快乐黑客!
它说“不要评价我”。 例如,如果您想将列表用作数据,而不是代码,那么您会在其前面添加一个引号。 例如,
(print '(+ 3 4))
打印“(+ 3 4)”,而(print (+ 3 4))
打印“7”
其他人回答这个问题令人钦佩,Matthias Benkard提出了一个很好的警告。
不要使用引用来创建您将要修改的列表。 该规范允许编译器将引用列表视为常量。 通常情况下,编译器会通过在内存中为它们创建单个值来优化常量,然后从常量出现的所有位置引用该单个值。 换句话说,它可以像一个匿名的全局变量一样对待常量。
这可能会导致明显的问题。 如果你修改一个常量,它可能很好地修改了完全不相关代码中相同常量的其他用法。 例如,你可以在某些函数中比较某个变量与'(1 1),并在一个完全不同的函数中,用'(1 1)开始一个列表,然后添加更多的东西。 在运行这些函数时,您可能会发现第一个函数不再适当地匹配事物,因为它现在试图将变量与'(1 1 2 3 5 8 13)比较,这是第二个函数返回的结果。 这两个函数是完全不相关的,但是由于使用了常量,它们相互影响。 即使更疯狂的坏影响也可能发生,就像完全正常的列表迭代突然无限循环一样。
当你需要一个常数列表时使用引号,比如比较。 当您要修改结果时使用列表。
链接地址: http://www.djcxy.com/p/60931.html