2010-06-06 84 views
2

我很困惑這個代碼是如何工作的:方案:與集合混淆!

(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

回答

7

套!不能改變列表(或任何其他結構,不像set-car/cdr!),但只能改變一個(在你的情況下,當地的變量)的綁定。

(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

根據懷疑論者的回答,l是一個本地綁定的變量,並通過set改變它!不會對m做任何事情。

如果你想先放過返回預期值,則需要後續通過返回本地綁定L的新值,就像這樣:

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

(28 88) 
1

set!只改變的結合一個符號,通常讓垃圾收集器消耗其原始值。它不改變數據,它重新塑造了一個符號。因此,例如(set! (car '(symbol symbol2)) 3)不起作用,即使第二個子表達式評估爲符號值。

要真正突變內存中的數據,必須使用set-car!,set-cdr!,set-vector!等形式之一。它們具有完全不同的語義,並且評估它們的第二個子表單,然後在內存中更新它所評估的數據,並更改與它共享內存的所有其他符號的值。

+0

您還可以使用foreach嗎? – yarian 2011-06-16 16:11:27

0

這不是關於變異vs rebinding。 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)