在clojure中,如何将宏应用于列表? [英] In clojure, how to apply a macro to a list?
问题描述
在clojure
中,apply
不能应用于宏.例如 (apply and [true false])
会引发异常.我正在考虑以下解决方法:
(defmacro apply-macro[func args] `(~func ~@args))
乍一看,它似乎工作得很好:
(apply-macro and [true 5]);5(应用宏和 [true 5 0]);0(let [a 0] (apply-macro and [true a]));0
但是,当我向它传递一个指向向量的变量时,它崩溃了.
(let [a [true]] (apply-macro and a));java.lang.IllegalArgumentException:;不知道如何从:clojure.lang.Symbol 创建 ISeq
多么令人失望啊!!!!
知道如何修复 apply-macro
吗?
问题在于 a
在编译时只是一个符号.因此,编译时宏无法查看它包含的内容并进行必要的扩展.因此,您需要在运行时使用 eval 扩展宏.>
一种方法是将宏包装在一个调用 eval 的函数中,这可以通过这个方便的functionize"宏来完成:
(defmacro 函数化 [macro]`(fn [& args#] (eval (cons '~macro args#))))(let [a [true]] (apply (functionize and) a))=>真的
如果你愿意,你也可以在函数化方面定义应用宏:
(defmacro apply-macro [宏参数]`(应用(功能化~宏)~参数))(让 [a [true false]] (应用宏和 a))=>错误的
说了这么多,我仍然认为最好的办法是在不需要的时候完全避免使用宏:它们会增加额外的复杂性,最好保留用于真正需要编译时代码生成的情况.在这种情况下,您不需要: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屋!