2009-06-12 34 views
19

我意識到宏觀俱樂部的第一條規則是不使用宏,所以下面的問題是在學習Clojure的比什麼都更打算作爲一個練習(我意識到這不一定是最好的宏使用)。幫我寫一個Clojure的宏觀系統會自動添加元數據的函數定義

我想編寫一個簡單的宏,它作爲一個常規的宏包裝器,並添加一些元數據到定義的函數。所以,我想有這樣的事情:

(defn-plus f [x] (inc x)) 

...拓展出這樣的事:

(defn #^{:special-metadata :fixed-value} f [x] (inc x)) 

原則上,這似乎並沒有那麼難了我,但我無法正確解析定義函數中的[args]和其他形式的細節。

作爲獎勵,如果可能的話我希望宏能夠處理所有的DEFN的不同形式(即帶或不帶文檔字符串,多個元數的定義,等等)。我在clojure-contrib/def包中看到了一些看起來可能有用的東西,但很難找到使用它們的示例代碼。

+0

很好的介紹...主要道具爲。 – Kekoa 2009-06-12 23:03:01

+0

爲什麼不使用宏?你在想C預處理器嗎? – Svante 2009-06-13 01:48:40

回答

18

更新時間:

我的回答的一個版本是不是很強勁。這似乎是這樣做的更簡單,更適當的方式,從clojure.contrib.def被盜:

(defmacro defn-plus [name & syms] 
    `(defn ~(vary-meta name assoc :some-key :some-value) [email protected])) 

user> (defn-plus ^Integer f "Docstring goes here" [x] (inc x)) 
#'user/f 
user> (meta #'f) 
{:ns #<Namespace user>, :name f, :file "NO_SOURCE_PATH", :line 1, :arglists ([x]), :doc "Docstring goes here", :some-key :some-value, :tag java.lang.Integer}

#^{}with-meta是不一樣的東西。有關它們之間差異的解釋,請參閱Rich關於Clojure mailing list的討論。這有點令人困惑,它在郵件列表上出現了很多次,例如,另請參閱here

注意def的一種特殊形式,它處理元數據有點古怪的語言的其他一些地區相比。它將var的元數據設置爲def,該元數據爲指定var的符號的元數據;這是上述工作的唯一原因,我想。請參閱Clojure源文件中中的DefExpr類,如果您想查看它的全部內容。

最後,Programming Clojure第216頁說:

通常你應該避免在宏展開讀者宏,因爲讀者宏在讀取時評估,宏擴展開始之前。