Ok, let's try to get this straight: my final intent is to provide a macro as an API to users which will look like:
(defscript [a b]
(println a))
The result has to be an instance of a Script
protocol, which looks like:
(defprotocol Script
(run [this model]))
The idea being that the first argument to defscript
is a list of symbols that needs to be bound to correspondent keys in the model
:
(.run (defscript [a b] (println a)) {:a 1}) ;; yields 1
I can't come up with any code that can effectively produce such effect, as I'm constantly hitting a wall when trying to use the model
parameter, since at macro expansion time it's just a symbol:
(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-
works fine if called directly:
(invoke- [a] {:a 1} (println a)) ;; prints 1
but it doesn't work when used within defscript
as model
can't be expanded correctly:
(.run (defscript [a] (println a)) {:a 1}) ;; prints nil
How can I get past this point and glue the pieces together?
It seems that basically, your argument vector is a shortcut for a destructuring binding:
That way, model is destructured at run time, as it should be.