Help me write a Clojure macro which automatically adds metadata to a function definition

人走茶凉 提交于 2019-12-03 04:52:51
Brian Carper

Updated:

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}

#^{} 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.

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.

Finally, page 216 of Programming Clojure says:

You should generally avoid reader macros in macro expansions, since reader macros are evaluated at read time, before macro expansion begins.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!