部分共享数据结构常见的lisp

时间:2017-01-24 10:54:58

标签: data-structures common-lisp

说我希望有两个列表(setq x '(1 2 3))(setq y (list 1 (cadr x) 3),但我希望(cadr y)实际指向(cadr x) 以便在(setf (cadr x) 'a)(cadr y)之后A而不是2。有没有办法做到这一点?

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单元格被更改并调用条件处理程序,该处理程序将对该更改执行某些操作...