Clojure:def在顶层之外使用时丢弃^:macro

时间:2013-09-16 02:07:24

标签: macros clojure metadata

如果我评估

(def ^:macro my-defn1 #'defn)

定义了名为'my-defn1'的宏,我可以像'defn'一样使用。

但是,如果我评估

(if true
  (def ^:macro my-defn2 #'defn))

'my-defn2'的var没有设置:宏元数据,我不能将它用作宏,即使'def'形式与前一种情况相同。

以下是完整代码(http://cljbin.com/paste/52322ba5e4b0fa645e7f9243):

(def ^:macro my-defn1 #'defn)

(if true
  (def ^:macro my-defn2 #'defn))

(println (meta #'my-defn1))    ; => contains :macro

(println (meta #'my-defn2))    ; => doesn't contain :macro!

(my-defn1 hello1 []
          (println "hello 1"))

(hello1)                       ; => prints "hello 1"

(my-defn2 hello2 []            ; => CompilerException: Unable to resolve 
  (println "hello 2"))         ;    symbol: hello2 in this context

是什么让这种行为与众不同?

1 个答案:

答案 0 :(得分:1)

Clojure的def不能真正有条件地应用。 def的文档是IMO在这方面不够强大。这不仅仅是糟糕的风格,它还会引发各种微妙的问题。

您应该只在顶层使用def,或者在顶层使用dolet表单。有条件地应用def会导致功能被分解为declare和后续条件def,但并不总是像您期望/喜欢的那样。

最好在顶级使用def,然后有条不紊地使用alter-var-root。或者使用(def my-var (if .. .. ..))。想想为什么你想要一个全局定义“消失”。