方案:与集合混淆!

时间:2010-06-06 17:18:41

标签: scheme racket

我对此代码的工作原理感到困惑:

(define m (list 1 2 3 '(5 8)))
(let ((l (cdr m)))
(set! l '(28 88))) ==>(1 2 3 (5 8))

(define o (list 1 2 3 '(5 8)))
(let ((l (cdr o)))
(set-car! l '(28 88))) ==> (1 (28 88) 3 (5 8))

为什么(set! l '(28 88)))没有更新m

4 个答案:

答案 0 :(得分:7)

设置!不能改变列表(或任何其他结构,不像set-car / cdr!),但只改变a(在你的情况下,本地 l )变量的绑定。

(define x 3)
(define f (lambda (x) (set! x 4)))
(define g (lambda (y) (set! x y)))
(f x)
x 
-> 3
(g 5)
x
-> 5

答案 1 :(得分:1)

根据怀疑论者的回答,l是一个本地绑定变量,并通过set更改它!我不会做任何事情。

如果您希望第一个让我们返回预期值,您需要通过返回本地绑定的l的新值来跟进,如下所示:

(define m (list 1 2 3 '(5 8)))
(let ((l (cdr m)))
(set! l '(28 88))
  l)

(28 88)

答案 2 :(得分:1)

set!仅更改符号的绑定,通常让垃圾收集器使用其原始值。它不会改变数据,它会重新绑定符号。因此,(set! (car '(symbol symbol2)) 3)之类的东西不起作用,即使第二个子表单求值为符号值。

要真正改变内存中的数据,必须使用set-car!set-cdr!set-vector!等形式之一。它们具有完全不同的语义,并且会评估它们的第二个子表单,然后在内存中更新它评估的数据,更改与其共享该内存的所有其他符号的值。

答案 3 :(得分:0)

这不是关于变异与重新绑定。 set!set-car!都会改变指针。在您的示例中,l最初指向该对的cdr,这也是一对。当您set! l时,您告诉它指向保留'(28 88)的新位置。

类似地,当你执行set-car!时,你会说car指针现在将指向位置B而不是其当前位置A,但A的内容不会发生变异。例如:


(define list1 '(2 3)) 
(define list2 (list 72 list1 55))
(set-car! (cdr list2) 99)

list1 ==> '(2 3) 
list2 ==> '(72 99 55)