带有防御性副本的 SETQ 或 SETF

SETQ or SETF With Defensive Copy

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

看来我需要的是深度复制+setter。复杂的因素是,有时实体的性质是未知的。它可能是一个数组,也可能是一个哈希表。它也可能是一个对象。

如有任何建议,我们将不胜感激。

您唯一需要的是 immutable 对象并且只更新绑定。 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)

pushpop 为您完成此操作。这是相同的代码:

(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),因为这会改变对象并且所有引用都将获得相同的对象,因为它们指向我更改的对象。

所以如果你有某种更复杂的状态,比如哈希 table,你需要把它变成一棵树,这样你就可以在每次更新时更改 log(n) 个节点,并且它将以相同的方式工作,旧引用仍然具有相同的状态。