组!和

时间:2018-05-19 17:44:42

标签: scheme

我在理解计划中的破坏性操作时遇到的问题似乎并不一致。也就是为什么bar在以下示例中没有改变

(define foo '(a b))
(define bar foo)
(set! foo '(c d))
foo
>(c d)
bar
>(a b)

然而,这会通过改变foo来改变标准

(define foo '(a b))
(define bar foo)
(set-car! foo 'c)
foo
>(c b)
bar
>(c b)

如果我理解正确的话,酒吧指的是foo的'两个例子中的汽车,但不知何故,旧的foo在使用套装时不会改变!在第一个。我无法在任何地方找到关于如何以及为何发生这种情况的答案。

2 个答案:

答案 0 :(得分:3)

别名并不意味着bar指向foo,而是bar指向foo指向(define foo (list 'a 'b)) (define bar foo) 的同一事物 目前。如果图片有帮助,这里有正在进行的框图和箭头图。在您的设置代码之后,您有:

foo

initial

现在,如果您第一次尝试运行,则会创建一个新列表,并将bar设置为指向该列表,而不会更改(set! foo (list 'c 'd)) 引用的任何内容。

foo

first

但是,如果您改为运行此代码,则会修改bar(set-car! foo 'c) 恰好指向的(共享)列表。

he he 5 5 5 5 5 5 5 5 5 5 5 
ne ne 5 5 5 5 5 5 5 5 5 5 5

second

答案 1 :(得分:1)

define生成一个变量。一个评估为对象位置的名称。

(define foo (list 'a 'b))

此处foo可能指向地址240。在评估foo时,您会得到240,因此(define bar foo)会生成指向内存中同一对象的第二个变量。地址不会显示在REPL中,因此您可以(a b),因为REPL会在地址240中打印出来。

内存中的这个对象是cons,因此每个对象只是指向内存中其他值的两个指针。因此当你这样做时:

(set-car foo 'c)

您正在通过将car指针从a的地址表示更改为c的地址表示来更改位于地址240的利弊。由于foobar都指向地址240处的同一个cons单元格,因此它们都会得到更改,因为它们指向相同的数据

如果使用set!,则只更改名称所指的值:

(set! foo (cons 'd (cdr foo)))

现在,这将更新变量指针,从指向240到其他地址。因此,您可以评估foobar,看看它们是不同的值:

foo ; ==> (d b)
bar ; ==> (c b)

此处foo可能位于地址256中。由于我们在cdr中使用旧值foo,因此我们知道它们的尾部是相同的:

(cdr foo)                 ; ==> (b)
(eq? (cdr foo) (cdr bar)) ; ==> #t

如果您set! bar使用其他值:

(set! bar foo)

现在,foobar都指向256,如果不再使用240,则该位置的对可能会被垃圾收集,但是{{1}原始cdr的{​​{1}}就是地址foo,该地址不会被垃圾收集,因为地址{cdr指向该地址{ 1}}。

注意:我已更改248的定义,因为您不允许cons 256这样的文字,因为它们是不可变的。 foo每次执行代码行时都会创建一个新的列表,并且可以确保地址不会被重用。 set-car

NB2:计划报告尽力避免指示如何存储值。因此,他们不会在报告中使用概念地址。 Scheme和CL的大多数实现都模拟了它们的数据非常相似。