Ответ 1
Обновлено:
Предыдущая версия моего ответа была не очень надежной. Это похоже на более простой и правильный способ сделать это, украденное с 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
- это не одно и то же. Для объяснения различия между ними см. Раздел "Богатое обсуждение" Clojure список рассылки. Все это немного сбивает с толку, и в списке рассылки появилось множество раз; см. также здесь.
Обратите внимание, что def
является специальной формой и обрабатывает метаданные немного странно по сравнению с некоторыми другими частями языка. Он устанавливает метаданные var
you def
fing в метаданные символа, который называет var; что единственная причина, по которой это работает, я думаю. См. Класс DefExpr
в Compiler.java
в источнике Clojure, если вы хотите увидеть все это.
Наконец, страница 216 Программирование Clojure говорит:
Обычно вы должны избегать макросов чтения в макрорасширениях, поскольку макросы читателя оцениваются во время чтения до начала макрораспределения.