Что касается очистки кода, я бы удалил макрос make-memories-constant
- вы можете просто сделать
(def MEMORIES @MEMORY)
или даже
(def MEMORY @MEMORY)
чтобы не загромождать ваше пространство имен другим вар. Пока вы ставите это после всех вызовов memorize
, это сохранит снимок MEMORY
со всеми memorize
d строками внутри.
Я бы сказал, что это на самом деле довольно чисто, так как фактический код, выполняемый во время выполнения, не отличается от того, что было бы без какого-либо memorize
-ing ...
Другой подход заключается в том, чтобы подготовить своего рода «структуру запоминания» в виде отдельного пространства имен, экспортирующего макрос, скажем, setup-memorization
, скажем, который может выглядеть примерно так ( просто грубый набросок , который выиграл ' не работает без некоторой полировки ... с обновленной (не очень тщательно) протестированной версией - это на самом деле работает! ... все же, пожалуйста, подстройте ее под свои нужды):
(ns memorization-framework)
(defmacro setup-memorization []
(let [MEMORY (gensym "MEMORY")
MEMORIES (gensym "MEMORIES")]
`(do (def ~MEMORY (atom []))
(defmacro ~'memorize [s#] (swap! ~MEMORY conj s#) s#)
(defmacro ~'get-memory [] @~MEMORY)
(defmacro ~'defmemories [~MEMORIES]
`(do (def ~~MEMORIES @~~MEMORY)
(ns-unmap ~~*ns* '~'~'get-memory)
(ns-unmap ~~*ns* '~'~'memorize)
(ns-unmap ~~*ns* '~'~MEMORY)
~~MEMORIES)))))
Тогда вам нужно use
пространство имен memorization-framework
, сделать (setup-memorization)
в верхней части пространства имен для настройки, вызвать memorize
, как вы делаете в своем примере кода, чтобы запомнить вещи и, наконец, использовать end-memorization
defmemories
для хранения коллекции строк где-то в Var и удаления временного Var, используемого для хранения атома, используемого для хранения во время конструирования, наряду с возможностью дальнейших вызовов memorize
из этого пространства имен. ( Макрос end-memorization
предназначен для того, чтобы просто возвращать коллекцию туда, откуда вы ее вызываете, когда вызывается без аргументов, или определять новую переменную Var для ее хранения, если дан один аргумент, который должен быть символом, который будет использоваться для Назовите Var. Обновление: я только что протестировал версию defmemories
, поэтому я оставляю ее здесь и удаляю вариант "возврата на место".)
Пример взаимодействия в REPL в пространстве имен foo
(заметка, я определил setup-memorization
в пространстве имен user
):
foo> (user/setup-memorization)
#'foo/defmemories
foo> (get-memory)
[]
foo> (memorize "foo")
"foo"
foo> (memorize "bar")
"bar"
foo> (get-memory)
["foo" "bar"]
foo> (defmemories quux)
["foo" "bar"]
foo> quux
["foo" "bar"]
foo> (get-memory)
; Evaluation aborted.
foo> (memorize)
; Evaluation aborted.
Те, "Оценка прервана". сообщения указывают, что вызовы get-memory
и memorize
генерируют исключения после вызова defmemories
. Это по замыслу, как уже упоминалось выше. Кроме того, get-memory
здесь в основном для облегчения тестирования / отладки.
Если вы собираетесь использовать все это только один раз, подход setup-memorization
может быть излишним, но я полагаю, что если вы будете использовать его больше, он лишит вас некоторого шаблона.