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?
The problem is that
ais 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:
If you like, you could also define apply-macro in terms of functionize:
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.