你给出的两个例子做了完全不同的事情。首先是在宏展开时间处评估修改的s表达式,这几乎肯定不是您想要的。
user=> (defmacro runargs-eval [args]
(eval (cons (first args) " buckaroo")))
#'user/runargs-eval
user=> (macroexpand '(runargs-eval (println "hi there")))
b u c k e r o o
nil
user=> (defmacro runargs [args]
`([email protected](cons (first args) " buckeroo")))
#'user/runargs
user=> (macroexpand '(runargs (println "hi there")))
(println \space \b \u \c \k \e \r \o \o)
没有多大的差别,如果你只是简单地评价一个s表达式,恰好包含调用您的宏,但如果你正在编译代码,使用您的宏(如的λ的主体),宏扩展发生在编译时:
user=> (defn say-hello-eval [x] (runargs-eval (println x)))
b u c k e r o o
#'user/say-hello-eval
user=> (say-hello-eval "hi there")
nil
user=> (defn say-hello [x] (runargs (println x)))
#'user/say-hello
user=> (say-hello "hi there")
b u c k e r o o
nil
宏是简单地接受一个未计算的表达式,并返回一个修改后的未计算的表达式的功能。如果你真的想评估表达式作为宏展开的一部分,这将是一个非常不寻常的情况 - 通常你的宏将返回修改的表达式,并让Clojure编译器负责在适当的时候评估它。
第二个示例中的语法引用并不是真的必要 - 语法引用的一般用例是,当您将宏参数插入包含符号的模板化表达式中时,该符号应解析为名称空间中的某些该宏被定义。
(defmacro runargs [args]
(cons (first args) " buckeroo"))
你能提供您所需的输出,无论是AST-明智的:如果宏是真正的s表达式的语法变换,那么你可以在像你的数据将任何其他Clojure的数据结构表达操作和打印的? (因为给定的代码不会打印'buckeroo',而是'b u c k e r o o',我不确定这是否是有意的。) – xsc 2015-03-03 11:39:16
我的歉意。我们假设这是有意的。 – hawkeye 2015-03-03 12:20:26
使用宏的'技巧'是实际上有一个清晰的图片,说明一旦宏展开后代码的外观。从这里,你可以确定你想要做什么的模板。一旦你有了这个,那么这个宏是非常直接的定义。在大多数情况下,你不希望宏对参数进行评估 - 它更多的是在编译时将参数重新排列成新的形式,然后在运行时进行评估。如果参数是(inc x )而不是一个println和一个字符串 - 在编译时什么是x?什么时候应该发生? – 2015-03-04 09:06:52