Списки свойств в Common Lisp относятся к какому-либо глобальному состоянию? - PullRequest
5 голосов
/ 08 января 2011

Приведенный ниже код имеет z в качестве локальной переменной, но он ведет себя так, как будто он глобальный:

(defun foo (m)
  (let ((z '(stuff nil)))
    (push m (getf z 'stuff))
    (print z)))

(foo 1)
(foo 2)
(foo 3)

Я ожидаю, что результат будет

(STUFF (1)) 
(STUFF (2)) 
(STUFF (3)) 
T

но при запуске с SBCL я вижу

(STUFF (1)) 
(STUFF (2 1)) 
(STUFF (3 2 1)) 
T

Почему это так? Это поведение свойственно спискам свойств?

1 Ответ

6 голосов
/ 08 января 2011

В foo, z связано с буквенным выражением '(stuff nil). Функция деструктивно изменяет z, тем самым деструктивно изменяя значение литерала. Как LISP ведет себя в подобных обстоятельствах, зависит от реализации. Некоторые реализации послушно изменят буквальное значение (как в вашем случае). Другие реализации помещают литералы в области памяти, доступные только для чтения, и потерпят неудачу, если вы попытаетесь изменить эти литералы.

Чтобы получить желаемое поведение, используйте COPY-LIST, чтобы сделать копию литерала, который можно безопасно изменить:

(defun foo (m)
  (let ((z (copy-list '(stuff nil))))
    (push m (getf z 'stuff))
    (print z)))
...