Lisp 帮助我编写一个Clojure宏,它会自动将元数据添加到函数定义中
我意识到宏俱乐部的第一条规则是不要使用宏,因此下面的问题更像是学习Clojure的练习,而不是其他任何东西(我意识到这不一定是宏的最佳使用) 我想编写一个简单的宏,它充当常规Lisp 帮助我编写一个Clojure宏,它会自动将元数据添加到函数定义中,lisp,clojure,macros,defn,Lisp,Clojure,Macros,Defn,我意识到宏俱乐部的第一条规则是不要使用宏,因此下面的问题更像是学习Clojure的练习,而不是其他任何东西(我意识到这不一定是宏的最佳使用) 我想编写一个简单的宏,它充当常规(defn)宏的包装器,最后向定义的函数添加一些元数据。所以我想要这样的东西: (defn-plus f [x] (inc x)) (defn #^{:special-metadata :fixed-value} f [x] (inc x)) …扩展到如下内容: (defn-plus f [x] (inc x)) (d
(defn)
宏的包装器,最后向定义的函数添加一些元数据。所以我想要这样的东西:
(defn-plus f [x] (inc x))
(defn #^{:special-metadata :fixed-value} f [x] (inc x))
…扩展到如下内容:
(defn-plus f [x] (inc x))
(defn #^{:special-metadata :fixed-value} f [x] (inc x))
原则上,这对我来说并不难,但我很难确定正确解析定义函数中的[args]
和其他形式的细节
作为奖励,如果可能的话,我希望宏能够处理所有不同形式的defn(即,有或没有docstring、多个arity定义等)。我在软件包中看到了一些可能有用的东西,但很难找到使用它们的示例代码。更新: 我以前的回答不是很有力。这似乎是一种更简单、更恰当的方法,从
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}
(定义宏定义加上[名称和符号]
`(defn~(vary meta name assoc:some key:some value)~@syms))
用户>(defn加上^f整数“Docstring在此”[x](inc x))
#'用户/f
用户>(元)
{:ns#,:name f,:file“NO_SOURCE_PATH”,:第1行,:arglist([x]),:doc“Docstring goes here”,:some key:some value,:tag java.lang.Integer}
#^{}
和带有meta的不是一回事。有关它们之间差异的解释,请参见Rich关于。这一切都有点混乱,而且在邮件列表中出现了很多次;另见示例
请注意,def
是一种特殊形式,与该语言的其他部分相比,它处理元数据有点奇怪。它将var
您要def
的元数据设置为命名var的符号的元数据;我认为,这是上述方法有效的唯一原因。如果您想了解所有内容,请参阅Clojure源代码中Compiler.java
中的DefExpr
类
最后,第216页说:
通常应避免在宏扩展中使用读卡器宏,因为读卡器宏是在宏扩展开始之前在读取时计算的
好的介绍。。。主要的道具。为什么不使用宏呢?你在考虑C预处理器吗?很有趣!但有没有一种方法可以更有效地实现这一点?在do
中包装defn
,然后破坏性地修改其元数据对我来说似乎有点奇怪。同样,我在defmacro
内部使用#^{:k:v}
语法的实验到目前为止都是彻底失败的……做任何类型的def
都不是一件很实用的事情,因为它破坏性地改变了全局调度表的状态但你是对的,我已经更新了我的答案。我之前的回答是删除def
通常使用的#^Integer标记元数据。谢谢,这更容易理解,而且这些链接看起来非常有用,尽管我仍然有点困惑(macroexpand-1'(defn plus foo[bar](baz)))为什么不显示with meta标记。试试(设置!打印meta true)然后看一下宏展开。您将看到元数据已应用于命名函数的符号<在宏返回之前,在宏体中执行带meta的code>
。请注意,它在宏中未被引用。