2013-02-28 63 views
1

我有以下的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 

我得到了我想要當我eval包裹論點的mul調用的答案:

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

但我不明白爲什麼它有必要這樣做:如果my-mul宏已經被直接定義(而不是通過另一個宏),它就會起作用。例如,以下工作正常:

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

爲什麼我看到這種行爲?


編輯:迴應評論,下面是發生故障的情況下,macroexpands(即不使用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) 
+0

調試提示:這是什麼macroexpand說明了什麼? – 2013-02-28 08:16:00

+0

剛剛添加他們 – 2013-02-28 08:39:44

回答

3

正如你展示,你的代碼'喜歡發射看起來像:

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

所以你需要語法引用我T和後綴以#所有當地人:

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

因此,你的宏觀發射宏應該是:

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

是的,你的回答比我的更詳細:) – hsestupin 2013-02-28 09:16:26

2
(defmacro create-my-macro [macroname] 
`(defmacro ~macroname [a# b#] 
    `(mul ~a# ~b#))) 
相關問題