SETQ или SETF с защитной копией - PullRequest
0 голосов
/ 05 ноября 2018

Мне интересно, как можно сделать что-то в Common Lisp следующим образом. Предположим, у меня есть объект (сущность), который является уникальным в определенное время. То, что я хотел бы сделать, это установить некоторую переменную для состояния этого объекта, как снимок в определенное время. Первоначальная сущность может затем развиваться. Однако я хотел бы убедиться, что переменная по-прежнему указывает на состояние этой сущности в прошлом.

Похоже, что мне нужно что-то вроде глубокой копии + сеттер. Осложняющим фактором является то, что порой природа сущности неизвестна. Это может быть массив или хеш-таблица. Это может быть и объект.

Любой совет приветствуется.

1 Ответ

0 голосов
/ 06 ноября 2018

Единственное, что вам нужно, это неизменяемые объекты и только обновлять привязки. setqsetf с символом в качестве первого аргумента) делает это отлично. Вот несколько примеров:

(defparameter *test* '(1 2))
(defparameter *test2* *test*) ; a copy
(setf *test* (cdr *test*))    ; *test* is (2), but *test2* is still (1 2)
(defparameter *test3* *test*) ; a new copy
(setf *test* (cons 3 *test*)) ; *test* is (3 2), but *test2* is still (1 2) and *test3* is still (2)

push и pop делает это для вас. Вот тот же код:

(defparameter *test* '(1 2))
(defparameter *test2* *test*) ; a copy
(pop *test*)                  ; *test* is (2), but *test2* is still (1 2)
(defparameter *test3* *test*) ; a new copy
(push 3 *test*)               ; (3 2), but *test2* is still (1 2) and *test3* is still (2)

Здесь я не делаю (setf (car *test*) 3), поскольку он мутирует объект, и все ссылки получат один и тот же объект, поскольку они указывают на объект, который я изменил.

Так что, если у вас есть какое-то более сложное состояние, такое как хеш-таблица, вам нужно будет превратить его в дерево, чтобы вы могли изменять log (n) узлов для каждого обновления, и оно будет работать таким же образом , что старые ссылки все еще имеют то же состояние.

...