奇怪地引用了《论Lisp》中的列表示例



On Lisp中的这段话确实令人困惑——不清楚返回引用的列表(如'(oh my))如何实际改变函数在未来的行为:下次调用时,返回的列表不会在函数中从头开始再次生成吗?

如果我们定义惊呼,使其返回值包含一个报价单,

(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)

可以更改功能中的列表:

(exclaim ’(fixnums and bignums and floats)) 
->  (FIXNUMS AND BIGNUMS AND FLOATS OH MY GOODNESS)

为了对这些问题进行有力的证明,应该写下:

(defun exclaim (expression)
  (append expression (list ’oh ’my)))

exclaim的最后一次调用到底是如何将单词goodness添加到结果中的?该函数没有引用任何外部变量,那么对nconc的单独调用实际上是如何改变exclaim函数的工作方式的呢?

a)修改literal列表的效果在Common Lisp标准中是未定义的。你在这里看到的例子是一种可能的行为。

(1 2 3 4)是一个文字列表。但是像(list 1 2 3 4)中那样对LIST的调用在运行时返回一个新保存的列表。

b) 列表是函数代码中的文字数据。每次调用都将返回该数据对象。如果你想在每次通话中提供一个新的列表,那么你需要使用list或COPY-list之类的东西。

c) 由于返回的列表始终是相同的文字数据对象,因此修改它可能会产生如上所述的效果。还可以想象,如果代码及其对象被分配在只读内存中,就会发生错误。然后修改列表将尝试写入只读内存。

d) 在处理源代码中的文字列表数据时,需要记住的一件事是:Lisp编译器可以自由地优化存储。如果一个列表恰好在源代码中多次出现,则允许编译器检测到这一点,并且只创建一个列表。所有不同的地方都会指向这个列表。因此,修改列表会产生这样的效果,即这些更改可能在几个地方可见。

这也可能发生在其他文字数据对象(如数组/向量)中。

如果您的数据结构是代码的一部分,则返回此内部数据结构,修改此数据结构,然后尝试修改代码。

还要注意,Lisp可以由解释器执行。解释器通常在Lisp源结构上工作——代码不是机器代码,而是将Lisp代码解释为Lisp数据。在这里,您可以在运行时修改源代码,而不仅仅是源代码中嵌入的数据。

相关内容

  • 没有找到相关文章

最新更新