我正在尝试编写一个宏,将调用重定向到执行此操作的函数。这是一种将所有已发布函数收集到顶级clj文件中的方法。 https://martinfowler.com/bliki/PublishedInterface.html
我想复制doc字符串和arglists,docstring工作正常,但不是argslists。我错过了什么?
(defmacro idef
[fname]
(let [sym (symbol (str "clojure.core/" fname))
metas (meta (find-var sym))
arglists (:arglists metas)
doc (:doc metas)]
;;`(def ~(with-meta fname {:doc doc :arglists arglists}))
`(def ~(with-meta fname {:doc doc})
~sym)))
(idef inc)
如果我使用注释行,我会得到
CompilerException clojure.lang.ArityException: Wrong number of args (0) passed to: PersistentVector, compiling:(interface.clj:22:1)
这只是将命名空间硬编码为clojure核心的示例。
这个问题非常相似,但你看我复制:doc部分没有问题,有什么特别之处:arglists
Help me write a Clojure macro which automatically adds metadata to a function definition
答案 0 :(得分:0)
您收到该错误,因为arglists本质上是一个列表,并使用~
拼接它会导致此列表进行评估。
让我用一个例子来解释:
user> (:arglists (meta #'clojure.core/inc))
([x])
当您尝试在宏中执行~(with-meta fname {:doc doc :arglists arglists})
时,您字面评估绑定到arglists
符号的表单。因此,在inc
的情况下,您实际上是在尝试这样做:
user> ([x])
ArityException Wrong number of args (0) passed to: PersistentVector clojure.lang.AFn.throwArity (AFn.java:429)
报告您收到的错误。
为避免这种情况,您需要阻止arglists
表单进行评估。实现此目标的方法之一是将其置于quote
调用中:
(defmacro idef
[fname]
(let [sym (symbol (str "clojure.core/" fname))
metas (meta (find-var sym))
arglists (:arglists metas)
doc (:doc metas)]
`(def ~(with-meta fname {:doc doc :arglists `(quote ~arglists)}) ~sym)))