Кажется, что есть недоразумение о том, что происходит, когда вы звоните:
(concatenate 'list args (list :mem program-memory))
Список аргументов args
и (list :mem program-memory)
используются для создания нового списка. Здесь вы могли бы использовать append
, вот так: (append args (list :mem program-memory)
. В обоих случаях исходные списки не изменены, но вы получаете список аргументов fre sh (который может разделять последний список, но это деталь).
Однако содержимое обоих списков входных данных и результирующий список идентичен , точно такие же объекты упоминаются в этих списках до и после объединения, неявная копия объектов отсутствует.
Давайте посмотрим:
(defclass something () ())
(defvar *something* (make-instance 'something))
Когда я оцениваю *something*
, результирующий объект печатается как #<SOMETHING {10091B1973}>
(напечатанное представление может различаться в разных реализациях; идентичность вашего объекта будет отличаться).
Если я поместу его в list и вызовите copy-list
, результирующий список по-прежнему будет иметь то же значение:
(let ((list (list *something*)))
(assert (eq (first list)
(first (copy-list list)))))
То же самое применимо, если вы храните списки внутри списка, они не будут копироваться рекурсивно без явного вызова копировать. На самом деле давайте попробуем тот же пример, который вы привели, но с ключевыми словами:
;; unrelated, but for this Advent of Code you are going to have
;; performance issues if you treat memory as a list, and not a vector.
;; Here I change it to a vector.
(defun mem/w (memory address value)
"Writes the value to memory at address"
(setf (svref memory address) value))
;; mem is now a keyword argument
(defun sum-op (a b o &key mem)
(mem/w mem o (+ a b)))
(let ((memory (vector 0 2 3 0 0 0 0 0))
(args (list 1 2 0)))
;; using the backquote/slice syntax for brevity
;; but the result is like concatenate/append
(apply #'sum-op `(,@args :mem ,memory))
memory)
Полученное состояние памяти:
#(3 2 3 0 0 0 0 0)
NB. Неопределенное поведение заключается в изменении самого списка аргументов.
Редактировать:
Возможно, вы связали саму память с аргументами, и в этом случае новый список, представляющий память, был используется в вызываемой функции, но если это так, то это ошибка, поскольку предполагается, что конкатенация изменяет только список аргументов, а не один из аргументов.