2011-03-10 89 views
8

我有兩個宏。第一個將符號作爲唯一參數(因爲它傳遞給def,需要一個符號)。第二個函數帶有一個符號列表,並且應該分別爲每個符號調用第一個符號。在clojure中,我如何從另一個宏評估宏的參數?

(defmacro m1 [s] 
    '(let [f# ... dynamic function definition ...] 
     (def ~s f#)) 

第二個宏應該取一個符號列表並將它們傳遞給第一個,但我無法讓它工作。我能想出的最好的是以下幾點:

(defmacro m2 [symbols] 
    `(for [s# ~symbols] (eval (read-string (str "(name.of.current.namespace/m1 " s# ")"))))) 

迫使s#它被傳遞給第一宏之前進行評估。它也被調用一個字符串列表,而不是一個符號列表。

這對我使用的庫很有用,庫中的所有功能都採用相同的兩個第一個參數。我試圖在我的命名空間中爲一些函數創建包裝函數,這些函數自動提供前兩個參數值,這些參數值對所有這些參數都是通用的。

任何想法,以改善這一點?

+1

爲什麼一個普通的FN是不是一種選擇嗎? '(defn m2fun [symbols](map m1 symbols))' – skuro 2011-03-10 13:43:02

+0

你可以使用部分嗎?我真的不明白問題所在。 – nickik 2011-03-10 15:10:02

回答

8

通常當你問如何讓兩個宏配合時,答案是不要讓它們成爲宏。我認爲我的博客文章macro-writing macros將有助於澄清。對於這種特殊的情況我可能會從註釋結合了兩種建議:

(defmacro build-simpler-functions [& names] 
    (cons 'do 
     (for [name names] 
      `(def ~(symbol (str "simple-" name)) 
      (partial ~name 5 10))))) ; if you always pass 5 and 10 

(build-simpler-functions f1 f2) 

這擴展到

(do 
    (def simple-f1 (clojure.core/partial f1 5 10)) 
    (def simple-f2 (clojure.core/partial f2 5 10))) 

它看起來像基本上你想要什麼。

編輯:如果你「總是」通過args作爲各功能是不同的,你可以這樣做:

(defmacro build-simpler-functions [& names] 
    (cons 'do 
     (for [[name & args] names] 
      `(def ~(symbol (str "simple-" name)) 
      (partial ~name [email protected]))))) 

(build-simpler-functions [f1 5 10] [f2 "Yo dawg"]) ; expansion similar to the previous 
+0

這是點亮的:(cons'do ...)和〜(符號s#...)做了這件事。這個想法正在解決哪些代碼正在執行以及哪些代碼正在被返回以及它們如何相互影響。 – 2011-03-10 18:12:12

+0

您可能也喜歡clojure.contrib.macro-utils.macrolet這樣的一次性宏。我不喜歡用宏來污染我的命名空間,我只用了一次,所以你可以寫(macrolet [(defpartial [&funcs](cons'do ...))](defpartial [f1 5 10] [f2'omg'更多'參數])) – amalloy 2011-03-10 18:27:42