说我希望有两个列表(setq x '(1 2 3))
和(setq y (list 1 (cadr x) 3)
,但我希望(cadr y)
实际指向(cadr x)
以便在(setf (cadr x) 'a)
说(cadr y)
之后A
而不是2
。有没有办法做到这一点?
答案 0 :(得分:4)
让我们假设x
是(list 1 2 3)
,因为变异文字在标准中有不确定的后果。
在您的示例中,您根本没有共享列表结构。你所拥有的是指向相同值的不同列表结构。 (setf (cadr x) 'a)
改变了x
的列表结构,因此它指向不同的值。它不会将值2
更改为其他内容。结果当然是你只换了一个地方。
使用共享列表结构会产生这样的效果:当列表变异时,列表中具有相同cons
的多个列表将获得新值:
(let ((tmp (list 2 3)))
(defparameter *x* (cons 1 tmp))
(defparameter *y* (cons 'a tmp)))
*x* ; ==> (1 2 3)
*y* ; ==> (a 2 3)
;; the cdr of both are the same
(eq (cdr *x*) (cdr *y*)) ; ==> t
;; mutating the cadr changes both since both list use the same cons
(setf (cadr *x*) 'q)
*x* ; ==> (1 q 3)
*y* ; ==> (a q 3)
共享可变对象
如果你有一个可以变异的对象值,就像一个可变的字符串,你可以直接改变它而不是改变cons
。
(let ((ele (copy-seq "ni"))) ; make ele mutable
(defparameter *x* (list ele 1 2 4))
(defparameter *y* (list 5 6 ele 7)))
*x* ; ==> ("ni" 1 2 4)
*y* ; ==> (5 6 "ni" 7)
;; mutating the string value, not the reference to the value
(setf (aref (car *x*) 1) #\o)
*x* ; ==> ("no" 1 2 4)
*y* ; ==> (5 6 "no" 7)
你可以制作一个框来概括所有类型:
(defstruct box (data))
(let ((ele (make-box :data "ni"))) ; make ele mutable
(defparameter *x* (list ele 1 2 4))
(defparameter *y* (list 5 6 ele 7)))
*x* ; ==> (#s(box :data "ni") 1 2 4)
*y* ; ==> (5 6 #s(box :data "ni") 7)
;; mutating the string value, not the reference to the value
(setf (box-data (car *x*)) 10)
*x* ; ==> (#s(box :data 10) 1 2 4)
*y* ; ==> (5 6 #s(box :data 10) 7)
当你注意到真正发生的事情时,一个盒子是一个结构,其值我们改变但是列表指向同一个盒子。
答案 1 :(得分:4)
通常这是不可能的。
想象一下,你有两个清单:
CL-USER 11 > (sdraw (list 1 2 3))
[*|*]--->[*|*]--->[*|*]--->NIL
| | |
v v v
1 2 3
CL-USER 12 > (sdraw (list 'a 'b 'c))
[*|*]--->[*|*]--->[*|*]--->NIL
| | |
v v v
A B C
您如何表示利弊细胞之间的联系?当你在第一个列表中更改第二个cons单元格的CAR时,你会如何改变第二个列表中的cons单元格呢?
一种方法是在机器下面有一个机制,它会检测到一个变化,然后会做一些事情。在Lisp机器上你可以看到内存位置,但是在普通的Lisp中这是不可能的。
或者,您可以更改CADR以执行某些操作来检测某些标记的缺点单元格的更改。同样,这不是简单的Common Lisp。
<强>游览强>
Clozure CL有一种观察cons细胞的机制:
? (setf l1 (list 1 2 3))
(1 2 3)
? (watch (cdr l1))
(2 3)
? (setf (cadr l1) 'a)
> Error: Write to the CAR of watched cons cell (2 3)
> Faulting instruction: #<X86-DISASSEMBLED-INSTRUCTION (movq (% rsi) (@ 5 (% rdi))) #x302000E1EA0D>
> While executing: CCL::SET-CADR, in process Listener(4).
因此,人们可以检测到cons单元格被更改并调用条件处理程序,该处理程序将对该更改执行某些操作...