【问题标题】:Copy :arglists into a clojure def将 :arglists 复制到 clojure def
【发布时间】:2017-12-01 15:49:52
【问题描述】:

我正在尝试编写一个将调用重定向到执行此操作的函数的宏。这是一种将所有已发布的函数收集到顶级 clj 文件中的方法。 https://martinfowler.com/bliki/PublishedInterface.html

我想复制文档字符串和参数列表,文档字符串可以正常工作,但参数列表不行。我错过了什么?

(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

【问题讨论】:

    标签: clojure


    【解决方案1】:

    您收到该错误是因为 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)))
    

    【讨论】:

    • 尝试过类似的方法,但没有意识到我可以在反引号内添加反引号。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2010-10-11
    • 1970-01-01
    • 2019-11-18
    • 2023-03-20
    • 1970-01-01
    • 2022-11-15
    • 2018-03-28
    • 2013-06-05
    相关资源
    最近更新 更多