Если функция может быть разрушительной, и вы ничего не можете с этим поделать, тогда ясно, что вам нужно сделать копии initial-state
.
Одна возможность избежать предварительной настройки того, какие данные содержит initial-state
, состоит в том, чтобы оставить предоставление операции копирования явно проблемой для вызывающей стороны или сделать ее универсальной операцией и полагаться на кого-то другого для предоставления метода.
;; Version 1: the caller must provide a function that
;; returns a new fresh initial state
(defun example (build-initial-state modify mod-list)
(loop for modification in mod-list
collecting (funcall modify (funcall build-initial-state) modification)))
;; Version 2: copy-state is a generic function that has been
;; specialized for the state type
(defun example (initial-state modify mod-list)
(loop for modification in mod-list
collecting (funcall modify (copy-state initial-state) modification)))
Первая версия является более общей, поскольку она позволяет состоянию быть любым объектом, в то время как во второй версии операция копирования зависит от типа объекта состояния (и это означает, что у вас не может быть двух вызывающих абонентов, одновременно использующих списки в качестве состояния с другой семантикой копирования). ).
Однако copy-state
- это общая операция, которую можно, вероятно, использовать в других местах, и она делает общее использование более удобным (вы не должны вместо этого передавать функции компоновщика); он также позволяет вводить другие общие операции, такие как compare-state
, write-state
, read-state
...