奇怪的口齿不清报情况-格雷厄姆是口齿不清,第37页
-
25-09-2019 - |
题
我的工作我的方式通过格雷厄姆的书籍"对口齿不清"并不能了解以下例在第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)))
任何人都不会明白什么会在这里?这是真的搞砸了我的心理模型是什么引用。
解决方案
nconc
是一种破坏性的操作,改变其通过改变其尾部的第一个参数。在这种情况下,这意味着恒定的列表'(oh my)
得到一个新的尾部。
要希望使这个清晰。这有点像这样:
; 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)
修复更换(list 'oh 'my)
这一点,因为不再有由所有杂被共享的常数。到exclaim
每次调用生成一个新的列表(list
功能在生活中的目的是为了创造全新的列表)。
其他提示
这是你引用的心智模型可能存在缺陷的观察是一个很好的一个,尽管它可能还是取决于心智模式是什么可能不适用。
首先,请记住,有各种阶段的程序执行。甲Lisp的环境必须首先的读强>程序文本到数据结构(列表,符号和各种文字数据诸如字符串和数字)。接着,它可以或不可以的编译强>这些数据结构成机器代码或某种中间格式的。最后,将得到的代码是的评估的强>(在机码的情况下,当然,这可简单地平均跳跃到相应的地址)。
让我们把编译的问题放在一边,并专注于阅读和评估阶段,假定(为了简化),该评估的输入结构读取读取器数据的列表。
考虑一个形式(QUOTE x)
其中 X 是一个对象的某些文本表示。这可能是符号文字作为(QUOTE ABC)
,列表文字作为(QUOTE (A B C))
,一个字符串作为(QUOTE "abc")
,或任何其他形式的文字。在读取阶段,读取器将读取形式为列表(称之为 Form1中),其第一个元素是符号QUOTE
并且其第二元件是对象的 X'其文本表示为 X 。请注意,我具体说,对象的 X'被存储的代表该表达式列表中下,即,在某种意义上说,它存储为的一个的一部分代码本身强>
现在它是评估的转变。评价者的输入是 Form1中,这是一个列表。因此,看起来在所述第一元件的 Form1中,和,已经确定它是符号QUOTE
,的它返回作为评价的结果的列表强>的第二元件。这是至关重要的一点。评价者返回列表的第二个元素进行评估,这是读者在第一执行阶段读取(在编译之前!)。 这就是它。没有什么神奇的吧,这是非常简单的,和显著,没有创建新的对象,并没有现有的复制。
因此,当你修改“援引名单”,正在修改的代码本身。自修改代码是一个非常令人困惑的事情,并且在这种情况下,该行为实际上是未定义的(因为ANSI Common Lisp的允许实现把代码只读存储器)。
当然,以上所述仅仅是一个心理模型。实现可以自由地实现各种方式的模型,而事实上,我知道没有实现的Common Lisp的,像我的解释,确实没有编译可言的。尽管如此,这是基本的想法。
在公共口齿不清。
请记住:
'(1 2 3 4)
上面是一个 文字的列表. 恒定的数据.
(list 1 2 3 4)
列表是一个功能,时返回一个电话 新的名单 与其参数为列表中的要素。
避免修改文字的名单。该效应不是标准化。想象一下,一个口齿不清,汇编所有恒定的数据变成一个只写存储器区。想象一下,一个口齿不清,需要不断列出并分享他们在整个职能。
(defun a () '(1 2 3)
(defun b () '(1 2 3))
一个口齿不清的编译可以创建一个名单,是共享通过这两种功能。
如果你修改的列表返回的功能
- 它可能不会改变
- 它可能会被改变
- 它可能是一个错误
- 它还可能改变清单返回的功能b
实现自由做他们喜欢什么。这个留有优化。