本文介绍了帮我写一个Clojure宏,该宏会自动将元数据添加到函数定义中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我意识到Macro Club的第一个规则是不要使用宏",因此以下问题比其他任何事情都更适合作为学习Clojure的练习(我意识到这不一定是最好的 use ).

I realize that the first rule of Macro Club is Don't Use Macros, so the following question is intended more as an exercise in learning Clojure than anything else (I realize this isn't necessarily the best use of macros).

我想编写一个简单的宏,将其用作常规(defn)宏的包装,最后将一些元数据添加到已定义的函数中.所以我想要这样的东西:

I want to write a simple macro which acts as a wrapper around a regular (defn) macro and winds up adding some metadata to the defined function. So I'd like to have something like this:

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

...展开为以下内容:

...expand out to something like this:

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

原则上,这对我来说似乎并不难,但是我很难确定使正确定义的功能中的[args]和其他形式正确解析的细节.

In principle this doesn't seem that hard to me, but I'm having trouble nailing down the specifics of getting the [args] and other forms in the defined function to be parsed out correctly.

作为奖励,如果可能的话,我希望宏能够处理所有不同形式的defn(即,带有或不带有文档字符串,多个arity定义等).我在 clojure-contrib/def 包中看到了一些有用的东西,但是很难找到使用它们的示例代码.

As a bonus, if possible I'd like the macro to be able to handle all of the disparate forms of defn (ie, with or without docstrings, multiple arity definitions, etc). I saw some things in the clojure-contrib/def package that looked possibly helpful, but it was difficult to find sample code which used them.

推荐答案

已更新:

我的回答的先前版本不是很可靠.这似乎是一种更简单,更正确的方法,是从clojure.contrib.def中盗窃的:

The previous version of my answer was not very robust. This seems like a simpler and more proper way of doing it, stolen from 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邮件列表.这有点令人困惑,并且在邮件列表中出现了很多次.另请参见例如,此处.

#^{} and with-meta are not the same thing. For an explanation of the difference between them, see Rich's discussion on the Clojure mailing list. It's all a bit confusing and it's come up a bunch of times on the mailing list; see also here for example.

请注意,def是一种特殊形式,与语言的其他某些部分相比,它处理元数据的方法有些奇怪.它将def fing的var的元数据设置为命名var的符号的元数据;我认为,这是上述方法起作用的唯一原因.如果要查看全部内容,请参见Clojure源文件中Compiler.java中的DefExpr类.

Note that def is a special form and it handles metadata a bit oddly compared with some other parts of the language. It sets the metadata of the var you're deffing to the metadata of the symbol that names the var; that's the only reason the above works, I think. See the DefExpr class in Compiler.java in the Clojure source if you want to see the guts of it all.

最后,编程Clojure 的第216页说:

Finally, page 216 of Programming Clojure says:

这篇关于帮我写一个Clojure宏,该宏会自动将元数据添加到函数定义中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-30 17:21