在clojure,如何应用宏到列表? [英] In clojure, how to apply a macro to a list?
问题描述
在 clojure
, apply
不能应用于宏。例如(apply和[true false])
引发异常。我正在考虑以下解决方法:
(defmacro apply-macro [func args]`(〜func〜@ args))
乍一看,它似乎工作得很好:
(apply-macro和[true 5]); 5
(apply-macro和[true 5 0]); 0
(let [a 0](apply-macro和[true a])); 0
但是,当我向它传递一个指向一个向量的变量时, p>
(let [a [true]](apply-macro和a)); java.lang.IllegalArgumentException:
;不知道如何创建ISeq从:clojure.lang.Symbol
什么失望!
任何想法如何解决 apply-macro
?
(defmacro functionize [macro]
`(fn [& args#](eval(cons'〜macro args#))))
(let [a [true]](apply(functionize和)a))
=> true
如果你愿意,你也可以在functionize方面定义apply-macro:
(defmacro apply-macro [macro args]
`(apply(functionize〜macro)〜args))
(let [a [true false]](apply-macro和a))
=> false
说完这些,我仍然认为最好的做法是避免宏完全并不是真正需要的:它们增加了额外的复杂性,最适合于你真正需要编译时代码生成的情况。在这种情况下,您不会: Alex Taggart的回答给出了一个很好的示例,说明如何在没有任何宏的情况下实现类似的目标,这在大多数情况下可能更合适。
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 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.
这篇关于在clojure,如何应用宏到列表?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!