#macros #clojure #reify
#макросы #clojure #reify
Вопрос:
Хорошо, давайте попробуем разобраться: моя конечная цель — предоставить пользователям макрос в качестве API, который будет выглядеть:
(defscript [a b]
(println a))
Результатом должен быть экземпляр Script
протокола, который выглядит как:
(defprotocol Script
(run [this model]))
Идея заключается в том, что первый аргумент to defscript
— это список символов, которые необходимо привязать к соответствующим ключам в model
:
(.run (defscript [a b] (println a)) {:a 1}) ;; yields 1
Я не могу придумать какой-либо код, который мог бы эффективно производить такой эффект, поскольку я постоянно натыкаюсь на стену при попытке использовать model
параметр, поскольку во время расширения макроса это просто символ:
(defmacro invoke-
[params model body]
(let [p (flatten (map (fn [x] [x (model (keyword x))]) params))]
`(let [~@p]
~body)))
(defmacro defscript
[params amp; body]
`(reify Script
(run [~'this ~'model]
(invoke- ~params ~'model ~@body))))
invoke-
работает нормально, если вызывается напрямую:
(invoke- [a] {:a 1} (println a)) ;; prints 1
но она не работает при использовании в defscript
as model
, не может быть правильно расширена:
(.run (defscript [a] (println a)) {:a 1}) ;; prints nil
Как я могу преодолеть этот момент и склеить части вместе?
Комментарии:
1. То, что вы описываете, звучит смутно, как функции, предоставленные
clojure.template
в.
Ответ №1:
Похоже, что в основном ваш вектор аргументов является ярлыком для деструктурирующей привязки:
(defscript [a b] body) -> (reify Script (run [this {:keys [a b]}] body))
Таким образом, модель разрушается во время выполнения, как и должно быть.