задавать!и псевдоним в схеме - PullRequest
0 голосов
/ 19 мая 2018

У меня проблема с пониманием деструктивных операций в схеме, которые кажутся непоследовательными.А именно, почему 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)

Если я правильно понимаю, bar указывает на foo в своем'машина в обоих примерах, но как-то старый фу не меняется при использовании set!в первом.Я нигде не могу найти ответ о том, как и почему это происходит.

Ответы [ 2 ]

0 голосов
/ 20 мая 2018

Псевдоним не означает, что bar указывает на foo, скорее, bar указывает на ту же вещь , которая foo указывает на в данный момент ,Если картинки помогают, вот диаграммы в виде прямоугольников и стрелок для того, что происходит.После вашего установочного кода у вас есть это:

(define foo (list 'a 'b))
(define bar foo)

initial

Теперь, если вы запускаете свою первую попытку, вы создаете новый список и устанавливаете foo указать на это, не меняя ничего о bar или о том, что это ссылок.

(set! foo (list 'c 'd))

first

Но если вывместо этого, запустив этот код, вы изменяете (общий) список, на который в данный момент указывают и foo, и bar.

(set-car! foo 'c)

second

0 голосов
/ 19 мая 2018

define делает переменную.Имя, которое оценивает местоположение объекта.

(define foo (list 'a 'b))

Здесь foo может указывать на адрес 240.При оценке foo вы получаете 240 назад, поэтому (define bar foo) создаст вторую переменную, которая указывает на тот же объект в памяти.Адреса не отображаются в REPL, поэтому вы увидите (a b), поскольку REPL печатает адрес по адресу 240.

Этот объект в памяти является cons, поэтому каждый из них - всего два указателя на другие значения в памяти.Таким образом, когда вы делаете:

(set-car foo 'c)

, вы меняете минусы, расположенные по адресу 240, изменяя указатель car с адресного представления a на адресное представление c.Так как foo и bar указывают на одну и ту же конс-ячейку по адресу 240, они оба получат изменение, поскольку они указывают на одинаковые данные .

Если вы используете 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, пара в этом месте может быть подвергнута сборке мусора, но с cdr оригинального fooэто cdr, скажем, адрес 248, этот адрес не будет собирать мусор, так как на него указывает cons в адресе 256.

Примечание: я изменил определение foo, поскольку вам не разрешено использовать set-car литералы, такие как '(a b), поскольку они неизменяемы.(list 'a 'b) создает новый список каждый раз, когда выполняется строка кода, и вы можете быть уверены, что адрес не используется повторно, например.'(d a b).

NB2. В отчете по схеме стараются не указывать, как хранить значения.Таким образом, они не используют адрес концепции в отчете.Большинство реализаций как Scheme, так и CL моделируют свои данные довольно схожими.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...