Схема: путаница с набором!

Я смущен, как работает этот код:

(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?


person superguay    schedule 06.06.2010    source источник


Ответы (4)


задавать! не может изменить список (или любую другую структуру, в отличие от set-car/cdr!), а только изменить привязку (в вашем случае, локальную 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
person Rhangaun    schedule 06.06.2010

Согласно ответу скептика, l была локально привязанной переменной и меняла ее через set! ничего не собирается делать с m.

Если вы хотите, чтобы первый let возвращал ожидаемое значение, вам необходимо в дальнейшем вернуть новое значение локально связанного l, например:

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

(28 88)
person G__    schedule 06.06.2010

set! изменяет только привязку символа, часто позволяя сборщику мусора использовать его исходное значение. Он не мутирует данные, он перепривязывает символ. Следовательно, такие вещи, как (set! (car '(symbol symbol2)) 3), не работают, даже если вторая подформа оценивается как символьное значение.

Чтобы действительно изменить данные в памяти, необходимо использовать одну из форм set-car!, set-cdr!, set-vector! и так далее. Они имеют совершенно другую семантику и действительно оценивают свою вторую подформу, и любые данные, которые он оценивает, затем обновляются в памяти, изменяя значение всех других символов, которые разделяют с ним эту память.

person Zorf    schedule 09.06.2010

Речь идет не о мутации и перепривязке. И 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)
person dimvar    schedule 09.06.2010