Common Lisp中defparameter定义嵌套列表的结构共享问题及解决
问题1:现象成因
SBCL编译代码时会对字面常量结构做优化:当代码中出现完全相同的字面列表(比如这里的'(a a a)),编译器会将它们合并为同一个列表对象,也就是「结构共享」。
你用(setf (caar *var*) 'c)修改的正是这个被共享的列表对象,所以首尾两个看似独立的列表其实指向同一块内存,修改后自然同时变化。
在REPL直接求值defparameter时,解释器会实时创建每个子列表,不会做这种编译级的结构共享优化,因此每个(a a a)都是独立对象,修改一个不会影响另一个。
另外需要注意:Lisp标准中,通过quote生成的字面常量属于不可修改的常量,修改它们本身是未定义行为——虽然SBCL没有严格禁止,但编译时的结构共享就是这种行为引发意外的典型场景。
问题2:正确定义方式
要在defparameter里定义独立的、内容相同的列表,不能用字面量'引用,而是要通过运行时函数调用创建新列表,确保每个子列表都是独立对象。标准写法是使用list函数:
(defparameter *var* (list (list 'a 'a 'a) (list 'a 'x 'a) (list 'a 'a 'a)))
list是函数,每次调用都会在运行时生成全新的列表结构,编译器不会对函数返回的对象做结构共享优化,这样三个子列表完全独立,修改其中一个不会影响其他。
内容的提问来源于stack exchange,提问作者anonymous
相关产品推荐
相关产品推荐

