переменная проблема в LISP - PullRequest
6 голосов
/ 15 июня 2011

Я пишу программу на Common Lisp, в которой мне нужна функция с такой базовой схемой:

(defun example (initial-state modify mod-list)
  (loop for modification in mod-list
        collecting (funcall modify initial-state modification)))

Проблема в том, что мне нужно, чтобы initial-state было одинаковым каждый раз, когда оно передается modify, но modify может быть разрушительным. Я просто сделал бы копию, но я не хочу делать предположения о том, что тип данных initial-state.

Как я могу это сделать? Или это вообще возможно?

Спасибо!

1 Ответ

7 голосов
/ 15 июня 2011

Если функция может быть разрушительной, и вы ничего не можете с этим поделать, тогда ясно, что вам нужно сделать копии 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 ...

...