【问题标题】:Clojure repeated `defmacro` wrapping a form that creates a Java classClojure 重复 `defmacro` 包装了一个创建 Java 类的表单
【发布时间】:2018-08-31 08:25:34
【问题描述】:

我用defmacro 包装defrecord,因为我想要一种特定类型的具体地图在中心位置注册自己(用于serde)。

宏是:

(defmacro def-thing! [name [& fields] & opts+specs]
  `(let [klass# (defrecord ~name ~fields ~@opts+specs)
         map-constructor-fn# (resolve (symbol (str 'map-> ~name)))]
     ; use the map-constructor-fn#
     ))

问题在于 let 表单根据之前是否已经调用过宏(比如我在 nrepl 中重新加载命名空间源文件时)以不同的方式进行宏扩展。

第一次,name 是一个符号。

第二次,name 是一个 Java 类。

当然,我可以测试name~ 是否是Java 类,然后调用.getSimpleName() 并做相应的事情。

但是 Clojure 的核心贡献者一定遇到过这种情况?这是如何处理的?为什么我没有在 Clojure 核心源代码中看到 defrecordemit-defrecord 的明确解决方案?我错过了什么?

【问题讨论】:

  • 不完全相关,只是为了澄清一下,参数列表不应该是[name fields & opts+specs]吗?还是您的调用语法与defrecord 不同?
  • 我从defrecord 签名中获取的[& fields] 表格。解构本质上是强制fields 成为seq 而不执行:pre 形式的简写。我想。

标签: clojure macros


【解决方案1】:

好吧,我是个白痴。我在“Clojure 的喜悦”中找到了这个:

(defmacro def-thing! [name [& fields] & opts+specs]
  `(let [klass# (defrecord ~name ~fields ~@opts+specs)
         map-constructor-fn# (resolve (symbol (str 'map-> '~name)))]
     ; use the map-constructor-fn#
     ))

注意(quote (unquote <symbol>)) - 即'~<symbol> - 形式。该成语强制捕获传入的原始、不合格的符号。

奇怪的是,我没有将它传递给defrecord 调用。在内部,defrecord 对原始符号进行相同的捕获,除了通过 var 调用,大概是因为 defrecord 在第一次调用时会将符号分配给完全限定的类 var。事实上,'~name 特别是defrecord 调用中不起作用,我得到了clojure.lang.Cons cannot be cast to clojure.lang.Named 异常。

这对我来说似乎不一致,但我知道什么?

【讨论】:

    猜你喜欢
    • 2017-09-25
    • 2014-10-23
    • 1970-01-01
    • 2014-04-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多