我在理解计划中的破坏性操作时遇到的问题似乎并不一致。也就是为什么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在使用套装时不会改变!在第一个。我无法在任何地方找到关于如何以及为何发生这种情况的答案。
答案 0 :(得分:3)
别名并不意味着bar
指向foo
,而是bar
指向foo
指向(define foo (list 'a 'b))
(define bar foo)
的同一事物 目前。如果图片有帮助,这里有正在进行的框图和箭头图。在您的设置代码之后,您有:
foo
现在,如果您第一次尝试运行,则会创建一个新列表,并将bar
设置为指向该列表,而不会更改(set! foo (list 'c 'd))
或 引用的任何内容。
foo
但是,如果您改为运行此代码,则会修改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
答案 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的利弊。由于foo
和bar
都指向地址240
处的同一个cons单元格,因此它们都会得到更改,因为它们指向相同的数据。
如果使用set!
,则只更改名称所指的值:
(set! foo (cons 'd (cdr foo)))
现在,这将更新变量指针,从指向240
到其他地址。因此,您可以评估foo
和bar
,看看它们是不同的值:
foo ; ==> (d b)
bar ; ==> (c b)
此处foo
可能位于地址256
中。由于我们在cdr
中使用旧值foo
,因此我们知道它们的尾部是相同的:
(cdr foo) ; ==> (b)
(eq? (cdr foo) (cdr bar)) ; ==> #t
如果您set!
bar
使用其他值:
(set! bar foo)
现在,foo
和bar
都指向256
,如果不再使用240
,则该位置的对可能会被垃圾收集,但是{{1}原始cdr
的{{1}}就是地址foo
,该地址不会被垃圾收集,因为地址{cdr
指向该地址{ 1}}。
注意:我已更改248
的定义,因为您不允许cons
256
这样的文字,因为它们是不可变的。 foo
每次执行代码行时都会创建一个新的列表,并且可以确保地址不会被重用。 set-car
。
NB2:计划报告尽力避免指示如何存储值。因此,他们不会在报告中使用概念地址。 Scheme和CL的大多数实现都模拟了它们的数据非常相似。