在Lisp中,为什么我们需要使用列表函数来返回列表?

bba*_*ker 2 lisp common-lisp

我本以为这会起作用:

(defun list-of-things (thing1 thing2 thing3)
  "returns a ???"
  '(thing1 thing2 thing3))
Run Code Online (Sandbox Code Playgroud)

但这实际上是返回列表所需的:

(defun list-of-things (thing1 thing2 thing3)
  "returns a list" 
  (list thing1 thing2 thing3))
Run Code Online (Sandbox Code Playgroud)

Num*_*bra 5

这是两个不同的东西,也是 Lisp 语言的核心概念。

该语法'(a b c)是 的简写形式(quote (a b c))quote是一种返回其参数unevaluated 的特殊形式。在这种情况下,它将是包含三个符号的列表。

另一方面,list是一个普通函数,它计算其参数并返回其值的列表。

更深入一点:在计算任何表达式之前,必须先阅读代码。Lisp 特有的部分(事实上,Common Lisp 更是如此)是“解析器”实际上只是一个 Lisp 函数,返回 Lisp 对象。然后将这些对象交给“评估器”,评估器对它们进行评估:

  • 当读取字符 时'(thing1 thing2 thing3),读取器知道这'是一个读取器宏,因此它读取(quote (thing1 thing2 thing3))。这是一个包含两个元素的列表,一个符号,另一个包含三个符号的列表。然后将该列表提供给求值器:它知道这是一种特殊形式,返回未求值的参数,因此它仅返回读者提供给它的quote列表。(thing1 thing2 thing3)
  • 另一方面,当读取 时(list thing1 thing2 thing3),阅读器还将其作为列表读取(这次包含 4 个符号),然后将其提供给评估器。现在,求值器看到第一个符号是list,一个函数,因此它评估参数(它确定符号thing1... 绑定到什么),将它们传递给函数list,等等。

所有这一切都是可能的,因为 Lisp代码是根据 Lisp对象(例如列表等)定义的。在“解析”(实际上称为读取)阶段之后,评估器实际上得到了一个实际的 Lisp 对象来评估。当谈论编译等时,事情当然会稍微复杂一些,但总体思路是相同的。运算quote符(缩写为')是一种“直接”访问读者创建的事物并“绕过”评估的方法。