Tim*_*ert 19 lisp macros clojure defn
我意识到宏俱乐部的第一条规则是不要使用宏,所以下面的问题更多的是作为学习Clojure的练习而不是其他任何东西(我意识到这不一定是宏的最佳用法).
我想编写一个简单的宏,它充当常规(defn)宏的包装器,并最终向定义的函数添加一些元数据.所以我想要这样的东西:
(defn-plus f [x] (inc x))
Run Code Online (Sandbox Code Playgroud)
......扩展到这样的东西:
(defn #^{:special-metadata :fixed-value} f [x] (inc x))
Run Code Online (Sandbox Code Playgroud)
原则上这对我来说似乎并不难,但是我无法[args]确定正确解析定义函数中的其他形式的具体细节.
作为奖励,如果可能的话,我希望宏能够处理所有不同形式的defn(即,有或没有docstrings,多个arity定义等).我在clojure-contrib/def包中看到了一些看起来可能有用的东西,但是很难找到使用它们的示例代码.
Bri*_*per 18
更新:
我的答案的先前版本不是很强大.这似乎是一种更简单,更正确的方式,从clojure.contrib.def以下方面被盗:
(defmacro defn-plus [name & syms]
`(defn ~(vary-meta name assoc :some-key :some-value) ~@syms))
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邮件列表的讨论.这有点令人困惑,它在邮件列表上出现了很多次; 另见这里的例子.
请注意,这def是一种特殊形式,与语言的其他部分相比,它有点奇怪地处理元数据.它将var您def的元数据设置为命名var的符号的元数据; 我认为这是上述工作的唯一原因.如果你想看到它的内容,请参阅Clojure源代码中的DefExpr类Compiler.java.
最后,Programming Clojure的第216页说:
您通常应该避免宏扩展中的读取器宏,因为在宏扩展开始之前,读取器宏在读取时进行评估.
| 归档时间: |
|
| 查看次数: |
3205 次 |
| 最近记录: |