Clojure макрос для сбора строк в константу - PullRequest
1 голос
/ 26 февраля 2010

У меня есть файл Clojure с большим количеством строковых констант.Я хочу собрать эти строки в коллекцию, обернув их в макрос.После нескольких попыток мне это удалось, но мое решение выглядит довольно отвратительно.

(ns Memorable)
(def MEMORY (atom []))
(defmacro memorize [s] (swap! MEMORY conj s) s)

(prn (str (memorize "hello") " brave new " (memorize "world")))  ;  test

(defmacro make-memories-constant [] `(def MEMORIES ~(deref MEMORY)))
(make-memories-constant)

Есть ли более элегантные решения для этой проблемы?

1 Ответ

1 голос
/ 26 февраля 2010

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

...