2009-06-12 35 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页说:

通常你应该避免在宏展开读者宏,因为读者宏在读取时评估,宏扩展开始之前。