前言:
有关the best way to write a macro(恕我直言)的概述,请参阅这个过去的问题。
答案:
您不应该在main 函数中定义宏。试试这个:
(ns demo.core)
(defmacro happy
[]
`(println "I'm happy!")) ; *** notice the backtick! ***
(defn -main [& args]
(println :expanded (macroexpand '(happy)))
(happy)
)
启动一个repl:
~/expr/demo > lein repl
demo.core=> (macroexpand '(happy))
;=> (clojure.core/println "I'm happy!")
我们看到它有效。尝试从命令行运行:
~/expr/demo > lein run
:expanded (happy) ; <= ***** OOOPS! *****
I'm happy!
尝试将单引号更改为语法引号(也称为反引号),然后运行:
(defn -main [& args]
(println :expanded (macroexpand `(happy)))
(happy))
~/expr/demo > lein run
:expanded (clojure.core/println I'm happy!)
I'm happy!
解释是语法引用将完全限定 Var happy => demo.core/happy(由于该语法,您可以在 happy 宏本身内部的 println Var 上看到相同的效果-引用)。这允许宏扩展正常工作。与单引号比较:
(defn -main [& args]
(println :expanded (macroexpand '(demo.core/happy)))
(happy))
~/expr/demo > lein run
:expanded (clojure.core/println I'm happy!)
I'm happy!
造成这种行为的原因是,在 REPL 中,我们从提示中看到我们在 demo.core 命名空间中,因此 happy 被解析为 demo.core/happy。但是,当我们使用lein run 时,请注意:
(defn -main [& args]
(println *ns*)
(println (ns-name *ns*)))
结果:
~/expr/demo > lein run
*ns* => #object[clojure.lang.Namespace 0xb625b00 "user"]
(ns-name *ns*) => user
我们看到*ns* 设置为user 命名空间,并且happy 无法解析为Var demo.core/happy,除非我们手动或在代码中使用syntax-quote 完全限定它。
您可以找到list of documentation here。请务必特别学习 Clojure CheatSheet。
对于宏,书Mastering Clojure Macros也不错。