奇怪的Lisp引用场景-Graham';s在Lisp上,第37页

奇怪的Lisp引用场景-Graham';s在Lisp上,第37页,lisp,common-lisp,literals,quoting,on-lisp,Lisp,Common Lisp,Literals,Quoting,On Lisp,我正在阅读格雷厄姆的书《关于Lisp》,无法理解第37页的以下示例: If we define exclaim so that its return value incorporates a quoted list, (defun exclaim (expression) (append expression ’(oh my))) > (exclaim ’(lions and tigers and bears)) (LIONS AND TIGERS AND BEARS OH MY) >

我正在阅读格雷厄姆的书《关于Lisp》,无法理解第37页的以下示例:

If we define exclaim so that its return value incorporates a quoted list, (defun exclaim (expression) (append expression ’(oh my))) > (exclaim ’(lions and tigers and bears)) (LIONS AND TIGERS AND BEARS OH MY) > (nconc * ’(goodness)) (LIONS AND TIGERS AND BEARS OH MY GOODNESS) could alter the list within the function: > (exclaim ’(fixnums and bignums and floats)) (FIXNUMS AND BIGNUMS AND FLOATS OH MY GOODNESS) To make exclaim proof against such problems, it should be written: (defun exclaim (expression) (append expression (list ’oh ’my))) 如果我们定义惊叹号,使其返回值 包含引用的列表, (defun感叹词(表达式) (附加表达式“(噢,我的))) >(惊呼)(狮子、老虎和熊) (狮子、老虎和熊哦,天哪) >(NCOC*'(善良)) (狮子、老虎和熊哦,我的天哪) 可以更改函数中的列表: >(感叹词(fixnums和bignums以及float)) (FIXNUMS和BIGNUMS和float噢,天哪) 要针对此类问题进行惊叹式证明,应写: (defun感叹词(表达式) (附加表达式(列出“oh”my)))
有人知道这里发生了什么吗?这严重破坏了我关于引用的思维模式。

ncoc
是一种破坏性的操作,它通过改变尾部来改变第一个参数。在本例中,这意味着常量列表
”(哦,天哪)
获得了一个新的尾部

希望能让这更清楚。有点像这样:

; Hidden variable inside exclaim
oh_my = oh → my → nil

(exclaim '(lions and tigers and bears)) =
    lions → and → tigers → and → bears → oh_my

(nconc * '(goodness)) destructively appends goodness to the last result:
    lions → and → tigers → and → bears → oh → my → goodness → nil
so now, oh_my = oh → my → goodness → nil
(列出'oh'my)
替换
(oh'my)
修复了这一问题,因为所有人和杂项不再共享常量。每次调用
感叹号
都会生成一个新列表(函数的作用是创建全新的列表)。

在Common Lisp中

记住:

'(1 2 3 4)
上面是一个文本列表恒定数据

(list 1 2 3 4)
LIST是一个函数,当调用返回一个新列表时,该列表将其参数作为列表元素

避免修改文字列表。效果不规范。设想一个Lisp将所有常量数据编译到一个只写的内存区域。想象一个Lisp,它获取常量列表并在函数之间共享它们

(defun a () '(1 2 3)

(defun b () '(1 2 3))
Lisp编译器可以创建一个由两个函数共享的列表

(defun a () '(1 2 3)

(defun b () '(1 2 3))
如果修改函数a返回的列表

  • 它可能不会改变
  • 它可能会改变
  • 这可能是个错误
  • 它还可能更改函数b返回的列表

实现有做自己喜欢做的事情的自由。这为优化留下了空间。

你的心理模型可能有缺陷,这是一个很好的观察,尽管它可能适用,也可能不适用,这取决于心理模型是什么

首先,记住程序执行有不同的阶段。Lisp环境必须首先将程序文本读入数据结构(列表、符号和各种文字数据,如字符串和数字)。接下来,它可能会也可能不会将这些数据结构编译成机器码或某种中间格式。最后,对结果代码进行评估(当然,对于机器代码而言,这可能仅仅意味着跳转到适当的地址)

让我们暂时把编译问题放在一边,重点放在阅读和评估阶段,假设(为了简单起见)评估者的输入是读者阅读的数据结构列表

考虑一个表单
(QUOTE x)
,其中x是对象的一些文本表示。这可能是
(QUOTE ABC)
中的符号文字、
(QUOTE ABC))
中的列表文字、
(QUOTE“ABC”)
中的字符串文字或任何其他类型的文字。在阅读阶段,读者将以列表的形式阅读表单(称之为form1),其第一个元素是符号
QUOTE
,第二个元素是对象x',其文本表示为x。请注意,我特别指出,对象x'存储在表示表达式的列表中,即在某种意义上,它存储为代码本身的一部分

(list 1 2 3 4)
现在轮到评估员了。评估者的输入是form1,它是一个列表。因此,它查看form1的第一个元素,并确定它是符号
QUOTE
作为计算结果返回列表的第二个元素。这是关键。求值器返回要求值的列表的第二个元素,这是读取器在第一个执行阶段(编译之前!)读取的内容这就是它的全部功能。它没有魔力,非常简单,而且重要的是,没有创建新对象,也没有复制现有对象

因此,无论何时修改“引用列表”,都是在修改代码本身。自我修改代码是一件非常令人困惑的事情,在这种情况下,行为实际上是未定义的(因为ANSI Common Lisp允许实现将代码放入只读内存)


当然,以上只是一个心理模型。实现可以自由地以各种方式实现该模型,事实上,我知道没有任何CommonLisp实现像我的解释那样根本不进行编译。不过,这是基本的想法。

那么(defun惊叹词(表达式)(附加表达式(list'oh'(oh my)))理论上也会有同样的问题,对吗?@mazemaster225:不,请看我的最新答案。公平地说,(list'oh'(oh my))的动作“变平”了吗符号oh_my包含在单独的组件“oh”和“my”中?对不起,我没有注意到您编写了一个稍微不同的列表。您的版本仍然没有问题,因为
”(哦,天哪)
被视为列表中的最后一个元素,而不是它的尾部。是这样的:
哦→ (哦→ 我的→ 零)→ 无
。不会发生扁平化。当然,如果您通过(例如,
cadr
访问最后一项,并将其传递给
NCOC
,您会看到相同的问题。在何种情况下,最好使用“(1 2 3 4)而不是(1 2 3 4)?关于:“上面是一个文字列表。常量数据”。我明白这是字面意思,但事实并非如此