【问题标题】:Clojure defmacro loses metadataClojure defmacro 丢失元数据
【发布时间】:2011-12-06 22:53:16
【问题描述】:

我正在尝试创建一个小的 Clojure 宏,它 defs 是一个带有类型提示的字符串:

(defmacro def-string [name value]
  `(def ^String ~name ~value))

(def-string db-host-option "db-host")

当我macroexpand它时,类型提示丢失:

(macroexpand '(def-string db-host-option "db-host"))
;=> (def db-host-option "db-host")

别介意打字暗示这一点的智慧。

为什么宏会丢失元数据?如何编写此宏或任何包含元数据的宏?

【问题讨论】:

    标签: macros clojure type-hinting


    【解决方案1】:

    ^ 是一个阅读器宏。 defmacro 永远看不到它。提示放在列表(unquote name) 上。例如比较(meta ^String 'x)(meta ' ^String x) 看看效果。

    你需要把提示放在符号上。

    (defmacro def-string
      [name value]
      `(def ~(vary-meta name assoc :tag `String) ~value))
    

    及用法:

    user=> (def-string foo "bar")
    #'user/foo
    user=> (meta #'foo)
    {:ns #<Namespace user>, :name foo, :file "NO_SOURCE_PATH", :line 5, :tag java.lang.String}
    

    【讨论】:

    • 啊!当然,阅读器宏在 defmacros 之前被评估。谢谢。
    【解决方案2】:

    元数据不会出现在宏展开中,因为它应该是“不可见的”。

    如果宏是正确的(它不是),您应该能够调用 (meta #'db-host-option) 来检查 var 上的元数据。

    注意 (def sym ...) 将元数据插入到它从符号接收的 var 上。但是 ^Tag ~name 将元数据设置在 ~name 上(取消引用名称),而不是在绑定到 name 的传入符号上。它不能做任何其他事情,因为^Tag ...处理是由阅读器完成的,一旦宏扩展开始,阅读器就已经完成了。

    你想要类似的东西

    (defmacro def-string [name value]
      `(def ~(with-meta name {:tag String}) ~value))
    
    
    user> (def-string bar 1)
    #'user/bar
    user> (meta #'bar)
    {:ns #<Namespace user>, :name bar, :file "NO_SOURCE_FILE", :line 1, :tag java.lang.String}
    

    【讨论】:

      猜你喜欢
      • 2014-10-23
      • 1970-01-01
      • 2015-11-23
      • 2013-02-04
      • 1970-01-01
      • 1970-01-01
      • 2021-05-25
      • 1970-01-01
      相关资源
      最近更新 更多