Схема: мутация локальной переменной в разных средах мутирует один и тот же объект

Рассмотрим эти две похожие процедуры:

(define (append-internal-cons obj)
  (let ((local-var (cons 1 '()) ))
    (append! local-var (list obj))
    local-var))

(define (append-internal-no-cons obj)
  (let ((local-var '(1) ))
    (append! local-var (list obj))
    local-var))

Учитывая эти две вспомогательные процедуры:

(define (append! x y)
  (set-cdr! (last-pair x) y)
            x)
(define (last-pair ls)
  (if (null? (cdr ls))
             ls
             (last-pair (cdr ls))))

Вызов первого из них три раза дает ожидаемые результаты: список, содержащий 1 и любое obj, которое мы передали.

(append-internal-cons 2) ;; (1 2)
(append-internal-cons 3) ;; (1 3)
(append-internal-cons 4) ;; (1 4)

Я бы ожидал, что вызов второй версии три раза даст те же результаты, но это не так.

(append-internal-no-cons 2) ;; (1 2)
(append-internal-no-cons 3) ;; (1 2 3)
(append-internal-no-cons 4) ;; (1 2 3 4)

Разве поведение двух процедур не должно быть одинаковым?


person plafer    schedule 28.05.2016    source источник
comment
Я могу ошибаться, но я считаю, что изменение литералов в кавычках является неопределенным поведением в стандарте Scheme. Таким образом, реализация может демонстрировать такое поведение, но не все реализации будут вести себя одинаково.   -  person Alexis King    schedule 28.05.2016
comment
Мутирующие литералы не допускаются в стандарте Scheme. Реализация схемы может свободно использовать один объект для всех вхождений '(1), поэтому это нарушение может даже изменить другие места. Большинство реализаций не сигнализируют об ошибке, поскольку это не требуется, поэтому вы получаете неожиданное поведение от программы, не относящейся к схеме (код, который нарушает отчет, не является кодом схемы)   -  person Sylwester    schedule 28.05.2016