Динамическая форма let как часть reify в макросе

#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))
 

Таким образом, модель разрушается во время выполнения, как и должно быть.