何时在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”)? 好。 否则会发生的是allocatefree的价值被抬头,我们不希望这样。 在我们的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

加起来

quotebackquote (用逗号)和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

上一篇: When to use ' (or quote) in Lisp?

下一篇: Why is Lisp used for AI?