为什么在函数调用之前没有评估我的宏的形式?

时间:2013-02-28 08:10:36

标签: macros clojure

我有以下Clojure代码:

(defn mul [a b]
  (* a b))

(defmacro create-my-macro [macroname]
    `(defmacro ~macroname [a# b#]
      (mul a# b#)))

(create-my-macro my-mul)

(my-mul 1 2)
;; => 2
(my-mul (+ 1 1) 2)
;; => ClassCastException clojure.lang.PersistentList cannot be cast to java.lang.Number

当我使用mul eval调用参数时,我得到了我想要的答案:

(mul (eval #a) (eval #b))

但是我不明白为什么有必要这样做:如果直接定义my-mul宏(而不是通过另一个宏),它就可以了。例如,以下工作正常:

(defmacro my-mul [a b] `(mul ~a ~b))
(my-mul (+ 1 1) 2)
;; => 4

为什么我会看到这种行为?


编辑:在回复评论时,以下是失败案例的宏观扩展(即不使用eval):

(macroexpand '(create-my-macro my-mul))
;; => (do
;;      (clojure.core/defn my-mul 
;;        ([&form &env a__58__auto__ b__59__auto__] 
;;          (foo/mul a__58__auto__ b__59__auto__)))
;;      (. (var my-mul) (setMacro)) (var my-mul))

(macroexpand '(my-mul (+ 1 1) 2))
;; => ClassCastException clojure.lang.PersistentList cannot be cast to java.lang.Number  clojure.lang.Numbers.multiply (Numbers.java:146)

2 个答案:

答案 0 :(得分:3)

如您所示,您要发出的代码如下:

(defmacro my-mul [a b] `(mul ~a ~b))

所以你需要语法引用它并使用#:

为所有本地人添加后缀
`(defmacro my-mul [a# b#] `(mul ~a# ~b#))

因此,您的宏发射宏应该是:

(defmacro create-my-macro [macroname]
    `(defmacro ~macroname [a# b#]
       `(mul ~a# ~b#)))

答案 1 :(得分:2)

(defmacro create-my-macro [macroname]
 `(defmacro ~macroname [a# b#]
   `(mul ~a# ~b#)))