Common lisp 具有防御性副本的SETQ或SETF

Common lisp 具有防御性副本的SETQ或SETF,common-lisp,deep-copy,shallow-copy,defensive-copy,Common Lisp,Deep Copy,Shallow Copy,Defensive Copy,我想知道如何在CommonLisp中做以下事情。假设我在内存中有一个对象(实体),它在某个时间是唯一的。我想做的是将某个变量设置为该对象的状态,作为特定时间的快照。原始实体随后可能会进化。但是,我想确保变量仍然指向该实体过去的状态 看来我需要的是类似于深拷贝+设置器的东西。复杂的因素是,有时实体的性质是未知的。它可以是一个数组,也可以是一个哈希表。它也可能是一个对象 非常感谢您的建议。您唯一需要的是不可变对象,并且只更新绑定setq(和setf,以符号作为第一个参数)可以完美地实现这一点。以下是

我想知道如何在CommonLisp中做以下事情。假设我在内存中有一个对象(实体),它在某个时间是唯一的。我想做的是将某个变量设置为该对象的状态,作为特定时间的快照。原始实体随后可能会进化。但是,我想确保变量仍然指向该实体过去的状态

看来我需要的是类似于深拷贝+设置器的东西。复杂的因素是,有时实体的性质是未知的。它可以是一个数组,也可以是一个哈希表。它也可能是一个对象


非常感谢您的建议。

您唯一需要的是不可变对象,并且只更新绑定
setq
(和
setf
,以符号作为第一个参数)可以完美地实现这一点。以下是一些例子:

(defparameter *test* '(1 2))
(defparameter *test2* *test*) ; a copy
(setf *test* (cdr *test*))    ; *test* is (2), but *test2* is still (1 2)
(defparameter *test3* *test*) ; a new copy
(setf *test* (cons 3 *test*)) ; *test* is (3 2), but *test2* is still (1 2) and *test3* is still (2)
push
pop
为您执行此操作。以下是相同的代码:

(defparameter *test* '(1 2))
(defparameter *test2* *test*) ; a copy
(pop *test*)                  ; *test* is (2), but *test2* is still (1 2)
(defparameter *test3* *test*) ; a new copy
(push 3 *test*)               ; (3 2), but *test2* is still (1 2) and *test3* is still (2)
这里我没有做的是
(setf(car*test*)3)
,因为这会改变对象,所有引用都会得到相同的对象,因为它们指向我更改的对象


因此,如果您有某种更复杂的状态,如哈希表,则需要将其转换为树,以便每次更新都可以更改日志(n)节点,并且它将以相同的方式工作,旧引用仍然具有相同的状态。

Common Lisp中没有通用的复制函数。您需要编写特定于所使用实体类型的浅层或深层复制函数。这就是为什么我们有像
copy-LIST
(列表的浅层复制)、
copy-TREE
(conses的深层复制)和
copy-SEQ
(列表或向量的浅层复制)这样的函数.没有内置函数来复制哈希表,你必须自己编写。这听起来像是您通常使用不可变数据结构(例如或)的情况。对于深度副本,您可以使用现有的序列化库,如您能详细说明最后一段吗?顺便问一下,如果数据结构本身引用了其他可能从其下更改的数据结构,这是否仍然有效?在本例中,我指的是哈希表中的值,这些值可能会从一个snapsnot更改为另一个snapsnot。物理学家认为,大多数函数数据结构都是树。你更新了三棵树,得到了一棵新的树。旧引用是完整的旧树,新引用是修改过的树。节点本身无法变异,但可以用新节点替换节点。这将创建一个包含日志(n)节点和新值的新树。另一种方法是每次深度复制,但由于这些值没有共享空间,因此需要使用更多的存储空间。