如何标记' Clojure数据结构中的节点?

时间:2014-05-24 15:01:59

标签: clojure clojurescript

我有

  • 一个Clojure数据结构,让我们称之为dom,一个向量树和 无限深度的地图;
  • 其中的特定节点,我们将其称为focus节点,称为 进入树的路径:您可以呈现的一系列键 get-in

我将在一个函数中决定聚焦节点,并且我想以某种方式表示聚焦节点的选择,其方式可以以不违反不变性的方式传递给另一个函数,并且与Clojure不冲突#39;持久性数据结构。

当我遍历树时,我想以不同的方式处理focus节点:例如,如果我打印树,我可能想要以粗体<打印focus节点/ strong>即可。

如果我使用的是C或Java,我可以保存指向focus节点的指针/引用,当我遍历树时,我可以将其与当前节点进行比较。我不认为这是在Clojure中做到这一点的正确方法:它感觉很乱,而且我确信有一些方法可以利用Clojure&#39;持久的数据结构。

解决方案必须适用于Clojure和ClojureScript。

我能想到的选择是:

  1. 存储参考文件并对其进行检查。
  2. 将标记附加到相关节点。
  3. 同时递归到树中并沿着指向标记节点的路径。

    • 正如我所解释的,选项(1)没有吸引力。
    • 选项(2)似乎是最好的,并且给定持久数据结构是无痛的。
    • 选项(3)类似于选项(2),除了它结合了 标记和遍历步骤。
  4. 我确定这是一个常见问题。它有标准的解决方案吗?

2 个答案:

答案 0 :(得分:2)

我建议你重新考虑@ MerceloMorales的建议:使用元数据。您的节点对象具有不会影响其正常功能的偶然属性。这就是元数据的设计目标。它适用于ClojureScript。我可以想到 not 使用元数据的唯一原因是节点值不是Clojure对象,而是例如一个数字。

The Clojure Cookbook, 2.22. Keeping Multiple Values for a Key中,Luke Vanderhart使用元数据来解决类似的问题:标记需要被解释为集合而不是单个值的条目。

另一种方法可能是使用拉链来遍历/修改节点树。拉链是根据 - 你猜对了 - 元数据来实现的。

我与您分享您对元数据的疑虑:将任何旧东西附加到您的数据中感觉很不舒服 - 就像用寄生虫感染它一样。然而,它与其他任何东西一样,是不可变的对象的一部分。


使用拉链的建议是天真的:standard clojure zippers是为顺序容器的层次结构设计的,而不是关联容器。

答案 1 :(得分:1)

请参阅Brandon Bloom的Dendrology talk,了解有关此类问题的一些精彩概述。

我认为“标记”或以其他方式更新树状结构数据的便利性是他强烈建议始终将节点表示为嵌套映射而不是向量(或向量和映射的混合)的基础。基于键向量描述的路径的标记就这么简单:

 (update-in tree-data path assoc :is-focussed true)

您的原始数据结构未更改,update-in返回的新数据结构在结构上与原始数据共享,除了更新的节点,现在可以在遍历时轻松测试:is-focussed属性。