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

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

问题描述

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

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