观察到你的引用心智模型可能有缺陷是一个很好的观察——尽管它可能适用也可能不适用,这取决于那个心智模型是什么。
首先,请记住程序执行有不同的阶段。Lisp 环境必须首先将程序文本读入数据结构(列表、符号和各种文字数据,如字符串和数字)。接下来,它可能会也可能不会将这些数据结构编译成机器代码或某种中间格式。最后,评估结果代码(当然,在机器代码的情况下,这可能只是意味着跳转到适当的地址)。
让我们暂时把编译的问题放在一边,专注于阅读和评估阶段,假设(为简单起见)评估者的输入是读者读取的数据结构列表。
考虑一种形式(QUOTE x)
,其中x是对象的某种文本表示。这可以是 in 中的符号文字、 in(QUOTE ABC)
中的列表文字、 in(QUOTE (A B C))
中的字符串文字(QUOTE "abc")
或任何其他类型的文字。在阅读阶段,读者会将表单读取为一个列表(称为form1),其第一个元素是符号QUOTE
,第二个元素是对象x',其文本表示为x。请注意,我是说对象x'存储在表示表达式的列表中,即在某种意义上,它存储为代码本身的一部分。
现在轮到评估者了。评估者的输入是form1,它是一个列表。因此,它查看form1的第一个元素,并在确定它是 symbolQUOTE
后,返回 list 的第二个元素作为评估结果。这是关键点。评估器返回要评估的列表的第二个元素,这是读者在第一个执行阶段(编译之前!)读入的内容。 这就是它所做的一切。 它没有魔法,它非常简单,而且重要的是,不会创建新对象,也不会复制现有对象。
因此,每当您修改“引用列表”时,您就是在修改代码本身。自修改代码是一件非常令人困惑的事情,在这种情况下,行为实际上是未定义的(因为 ANSI Common Lisp 允许实现将代码放入只读内存中)。
当然,以上只是一个心智模型。实现可以自由地以各种方式实现模型,事实上,我知道没有任何 Common Lisp 实现,就像我的解释一样,根本不进行编译。不过,这是基本思想。