Clojure:如何模拟向流中的字符添加元数据?

时间:2012-12-13 13:25:56

标签: clojure metadata

有一个返回seq字符的函数,我需要修改它以允许将元数据附加到某些字符(但不是全部)。 Clojure不支持基元类型的'with-meta'。因此,可能的选择是:

  • 返回[character,metadata]的一系列向量;
    专业人士:简单,数据和元数据紧密相连
    缺点:需要从矢量中提取数据
  • 返回两个单独的seq,一个用于字符,一个用于元数据,如果他关心元数据,则调用者最多同时迭代这些seq;
    例证:调用者不会被迫从每个流元素中提取数据,如果他愿意,可能会抛弃元序列
    缺点:需要一次迭代两个seq,如果需要元数据,则需要在调用方更复杂
  • 介绍一些包含一个字符的记录包装器,允许将meta附加到自身(Clojure记录实现IMeta);
    专业人士:数据和元数据捆绑在一起
    缺点:需要从记录中提取数据
  • 你更好的选择。

哪种方法更好?

1 个答案:

答案 0 :(得分:1)

使用矢量/地图序列,例如

({:char 'x' :meta <...>} {:char 'y' :meta <...>} {:char 'z' :meta <...>} ...)
; or
(['x' <...>] ['y' <...>] ['z' <...>] ...)

对我来说似乎是最好的选择,如果我有这样的任务,那就是我自己做的事情。然后,例如,编写一个将这种序列转换回字符序列的函数非常简单:

(defn characters [s] (map :char s))
; or
(defn characters [s] (map first s))

使用解构绑定也可以非常轻松地同时迭代字符和元数据:

(doseq [{:keys [char meta]} s] ...)
; or
(doseq [[char meta] s] ...)

使用什么(地图或矢量)主要取决于个人偏好。

IMO,使用记录及其IMeta界面并不是很好:我认为这种元数据主要用于与语言相关的代码(宏,代码预处理,语法扩展等),而不是域码。当然,我在这个假设中可能是错的。

使用两个并行序列是最糟糕的选择,因为它对于单个序列的接口用户来说并不方便。使用我上面编写的函数丢弃元数据非常简单,如果所有序列都是惰性的,它甚至都不会产生性能影响。