I’m trying to write a clojure macro that lets me call a function and retrieve the arguments from a map/struct using the provided key values such as:
(with-params {:apple 2 :banana 3 :cherry 7} + :apple :banana)
;; 5
but when I try to use the macro that I wrote:
(defmacro with-params [s f & symbols]
`(~f ~@(map ~s ~symbols)))
calling
(with-params {:apple 2 :banana 3 :cherry 7} + :apple :banana)
gives me
#<CompilerException java.lang.IllegalStateException: Var clojure.core/unquote is unbound. (NO_SOURCE_FILE:0)>
Could someone help me understand how syntax-quoting works here?
The reason that
`(~f ~@(map ~s ~symbols))doesn’t work is that the compiler chokes on the unnecessaryunquote(~) inside theunquote-splicing(~@). Theunquote-splicingunquotes the outersyntax-quote(`), so the inner twounquotes don’t have any matchingsyntax-quote, which is why you were getting the “unbound” error.What you want to do is evaluate
(map s symbols)first to get the sequence of operands, then pass the flattened result to the function (~f); therefore the correct version is:You can easily verify this with: