在clojure,如何应用宏到列表? [英] In clojure, how to apply a macro to a list?

查看:72
本文介绍了在clojure,如何应用宏到列表?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

a 在编译时只是一个符号。因此,编译时宏无法看到它包含什么并做必要的扩展。因此,您需要使用 eval 在运行时展开宏。

$ b $一种方法是将宏包装在调用eval的函数中,这可以用这个方便的functionize宏来完成:

 (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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆