In clojure
, apply
cannot be applied to a macro. For instance (apply and [true false])
raises an exception. I was thinking about following workaround:
(defmacro apply-macro[func args] `(~func ~@args))
At first glance, it seemed to work pretty well:
(apply-macro and [true 5]); 5 (apply-macro and [true 5 0]); 0 (let [a 0] (apply-macro and [true a])); 0
But, when I passed to it a variable that points to a vector, it collapsed.
(let [a [true]] (apply-macro and a)); java.lang.IllegalArgumentException: ;Don't know how to create ISeq from: clojure.lang.Symbol
What a disappointment!!!!
Any idea how to fix apply-macro
?
You don't.
Macros are expanded during evaluation/compile time, not at runtime, thus the only information they can use are the args passed in, but not what the args evaluate to at runtime. That's why a literal vector works, because that literal vector is there at compile time, but a
is just a symbol; it will only evaluate to a vector at runtime.
To have and
-like behaviour for lists, use (every? identity coll)
.
To have or
-like behaviour for lists, use (some identity coll)
.
The problem is that a
is just a symbol at compile time. So there's no way for a compile-time macro to see what it contains and do the necessary expansion. As a result, you need to expand the macro at run-time using eval.
One way to do this is just to wrap the macro in a function that calls eval, which can be done with this handy "functionize" macro:
(defmacro functionize [macro] `(fn [& args#] (eval (cons '~macro args#)))) (let [a [true]] (apply (functionize and) a)) => true
If you like, you could also define apply-macro in terms of functionize:
(defmacro apply-macro [macro args] `(apply (functionize ~macro) ~args)) (let [a [true false]] (apply-macro and a)) => false
Having said all this, I still think the best thing to do is to avoid macros entirely when they are not really needed: they add extra complexity and are best reserved for cases when you really need compile time code generation. In this case you don't: Alex Taggart's answer gives a good example of how to achieve a similar objective without any macros, which is probably more appropriate in most situations.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With