Clojure元数据在某些表单上丢失

时间:2016-09-16 21:48:33

标签: clojure metadata

我对以下表达式的行为差异感到困惑:

(pr (meta ^{:a 0} (list 1 2))) ;; prints nil returns nil

(pr (meta ^{:a 0} '(1 2)));; prints {:line 110, :column 20} returns nil

(pr (meta ^{:a 0} (range 1 3))) ;; prints nil returns nil

(pr (meta ^{:a 0} [1 2])) ;; prints {:a 0} returns nil

这是使用clojure 1.8.0。我欢迎解释为什么结果不同。

1 个答案:

答案 0 :(得分:5)

阅读器元数据附加到阅读器返回的表单。在每种情况下,meta都是以运行时评估的形式调用的。一个与另一个之间没有必要的联系。

如果需要在运行时将元数据附加到值,可以使用with-meta来执行此操作。

让我们看一下问题中列出的每种情况会发生什么:

  1. (pr (meta ^{:a 0} (list 1 2)))

    Reader元数据附加到列表结构(list 1 2),但meta不应用于此列表结构,而是应用于它在运行时评估的值,这将是新分配的两个列表没有附加元数据的项目。

  2. (pr (meta ^{:a 0} '(1 2)))

    Reader元数据附加到列表结构(quote (1 2))(单引号字符是(quote …)的读者简写),但meta不应用于此列表结构,而是应用于值它在运行时求值,这是读者在读取此表达式时创建的(1 2)列表结构。这带有{:line … :column …}元数据,因为Clojure读者将其附加到某些类型的表单以用于错误消息等。

  3. (pr (meta ^{:a 0} (range 1 3)))

    与上述第一个案例相同。

  4. (pr (meta ^{:a 0} [1 2]))

    这与'(1 2)情况非常相似,但关键的区别在于,如果非空列表不被视为函数/宏调用,则需要引用,而向量则不需要,因此读者元数据实际上附加到感兴趣的文字 - 矢量 - 本身。

    这也适用于列表:

    (pr (meta ' ^{:a 0} (1 2)))
              ^ note the quote comes before the metadata
    ;; prints {:line 1, :column 14, :a 0}
    

    NB。显式读者元数据地图已合并到读者自己添加的{:line … :column …}地图中。