2014-10-31 25 views
7

我正在試驗clojure宏,並想知道我可能做錯了什麼?clojure宏 - 不知道如何創建ISeq從:clojure.lang.Symbol

我有一個簡單的例子,試圖動態創建基於地圖的功能。

例如:

(def units {:cm 100 
      :mm 1000 
      :m 1 
      :km 1/1000}) 

(defn m-to-unit-helper [[k v]] 
    (let [f (symbol (str "to-" (name k)))] 
    `(defn ~f [m#] (* ~v m#)))) 

(defmacro m-to-units [units-map] 
    (let [funcs (map m-to-unit-helper units-map)] 
    `(do [email protected]))) 

; complains with: Don't know how to create ISeq from: clojure.lang.Symbol 
(m-to-units units) 

; To try and debug 
(defn debug [units-map] 
    (let [funcs (map m-to-unit-helper units-map)] 
    (clojure.pprint/pprint `(do [email protected])))) 

; see below 
(debug units) 

宏不起作用,但調試輸出的樣子應該建立正確的結構:

(do 
(clojure.core/defn 
    to-mm 
    [m__32709__auto__] 
    (clojure.core/* 1000 m__32709__auto__)) 
(clojure.core/defn 
    to-m 
    [m__32709__auto__] 
    (clojure.core/* 1 m__32709__auto__)) 
(clojure.core/defn 
    to-cm 
    [m__32709__auto__] 
    (clojure.core/* 100 m__32709__auto__)) 
(clojure.core/defn 
    to-km 
    [m__32709__auto__] 
    (clojure.core/* 1/1000 m__32709__auto__))) 

任何意見將不勝感激。謝謝。

回答

5

m-to-units是一個宏,這意味着每個參數都將被傳遞而不被評估,這意味着在宏內部units-map的值實際上是符號units。現在

,如果直接通過地圖,它會工作打算:

(m-to-units {:mm 1000, :m 1, :cm 100, :km 1/1000}) 
;; => #'user/to-km 

(to-cm 10) 
;; => 1000 

你可以做什麼 - 雖然我認爲這是不好的做法 - 用eval得到實際值的單位地圖,無論它是通過地圖還是通過符號:

(defmacro m-to-units 
    [units-map] 
    (let [funcs (map m-to-unit-helper (eval units-map))] 
    `(do [email protected]))) 

(m-to-units units) 
;; => #'user/to-km