来自On Lisp的奇怪的引用列表示例

joh*_*ers 9 lisp common-lisp literals on-lisp

这段经文On Lisp真的让人感到困惑 - 目前尚不清楚返回引用列表'(oh my)如何能够真正改变函数未来的行为方式:不会在函数中从头开始再次生成返回的列表,下一次是叫什么名字?

如果我们定义exclaim以使其返回值包含引用列表,

(defun exclaim (expression) 
  (append expression ’(oh my)))
Run Code Online (Sandbox Code Playgroud)

然后任何后来破坏性修改返回值

(exclaim ’(lions and tigers and bears)) 
->  (LIONS AND TIGERS AND BEARS OH MY)
(nconc * ’(goodness))
->  (LIONS AND TIGERS AND BEARS OH MY GOODNESS)
Run Code Online (Sandbox Code Playgroud)

可以改变函数中的列表:

(exclaim ’(fixnums and bignums and floats)) 
->  (FIXNUMS AND BIGNUMS AND FLOATS OH MY GOODNESS)
Run Code Online (Sandbox Code Playgroud)

为了对这些问题作出惊呼证据,应写成:

(defun exclaim (expression)
  (append expression (list ’oh ’my)))
Run Code Online (Sandbox Code Playgroud)

最后一次调用exclaimgoodness结果添加到结果中的确切方式是什么?该函数没有引用任何外部变量,那么单独的调用如何nconc实际改变exclaim函数的工作方式?

Rai*_*wig 10

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

(1 2 3 4)是一个文字列表.但是对于LISTlike 的调用会(list 1 2 3 4)在运行时返回一个新的consed列表.

b)列表是函数代码中的文字数据.每次调用都将返回此数据对象.如果您想在每次通话时提供新的清单,那么您需要使用LIST或COPY-LIST之类的东西.

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

d)在源代码中处理文字列表数据时要记住的一件事是:Lisp编译器可以自由地优化存储.如果源代码中的列表多次发生,则允许编译器检测到该列表并仅创建一个列表.然后所有各个地方都会指向这一个列表.因此,修改列表会产生这样的影响,即这些更改可能在多个位置可见.

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

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

另请注意,Lisp可以由Interpreter执行.解释器通常用于Lisp源代码结构 - 代码不是机器代码,而是将Lisp代码解释为Lisp数据.在这里,您可以在运行时修改源代码,而不仅仅是源代码中嵌入的数据.