Хорошо, давайте попробуем разобраться: мое последнее намерение - предоставить пользователям макрос в виде API, который будет выглядеть следующим образом:
(defscript [a b]
(println a))
Результатом должен быть экземпляр протокола Script
, который выглядит следующим образом:
(defprotocol Script
(run [this model]))
Идея состоит в том, что первый аргумент 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 & body]
`(reify Script
(run [~'this ~'model]
(invoke- ~params ~'model ~@body))))
invoke-
работает нормально, если вызывается напрямую:
(invoke- [a] {:a 1} (println a)) ;; prints 1
, но он не работает при использовании в defscript
, так как model
не может быть правильно расширен:
(.run (defscript [a] (println a)) {:a 1}) ;; prints nil
Как мне пройти этот пункт и склеить кусочки?