在clojure中序列化持久数据结构

时间:2015-07-03 10:39:11

标签: serialization clojure

我们都知道Rich使用理想的基于哈希树的方法来实现Clojure中的持久数据结构。这种结构使我们能够操作持久数据结构而无需复制很多。

但似乎我找不到正确的方法来序列化这个特定的结构。例如:

(def foo {:a :b :c :d})
(def bar (assoc foo :e :f))
(def bunny {:foo foo :bar bar})

我的问题是:

如何序列化bunny,以便foo的内容,即:a映射到:b:c映射到:d ,在序列化内容中只出现一次?这就像倾倒结构的记忆图像。它也像序列化“内部节点”以及引用here的“叶子节点”。

PS 如果这是相关的,我正在构建一个大的DAG(有向非循环图),我们assoc将这些节点链接到这些节点并想要序列化DAG用于以后的反序列化。图表的扩展表示(即,在repl中打印DAG时将获得的内容)是不可接受的长。

2 个答案:

答案 0 :(得分:1)

Davyzhu,

首先要做的事情很少:

  1. 没有标记化策略的DAG将与DAG一样长。如果引用foo一次或多次,则在打印过程中将依次完全实现(即显示)。
  2. 对于信息的交换(序列化和反序列化),它在很大程度上取决于您的目标。例如,如果您要序列化以通过线路将其发送出去,则您将要完全执行此操作(如打印表示),或者您需要使用某些标识/标记化策略对单个数据点进行编码。当然,后者假设接收端可以通过理解标记化协议来反序列化。
  3. 标记化策略示例可能使用Clojure meta工具,可能需要为每个内容块引用编码唯一键,而DAG包含边缘由键表示的节点。
  4. 编辑:自原始帖子修改后,根据评论澄清但是示例 不反映DAG的层次性。

    一个人为的例子:

    (def node1 {:a :b :c :d})
    (def node2 {:e :f})
    (def dictionary {:foo node1 :bar node2})
    
    (def DAG [:bunny [:foo :bar]])
    
    (println DAG) ; => [:bunny [:foo :bar]]
    
    (defn expand-dag1
      [x]
      (if (keyword? x)
        (get dictionary x x)
        x))
    
    (println (w/postwalk expand-dag1 DAG)) ; => [:bunny [{:a :b, :c :d} {:e :f}]]
    

    注意:使用向量,地图,列表等来表达您的DAG取决于您。

答案 1 :(得分:1)

这是一个选项(在Clojurescript中不起作用,如果重要的话)并且通常可能被认为是一个坏主意,但无论如何都值得一提。

如果我理解了您的问题,您希望foo中的(def bunny {:foo foo :bar bar})不被粘贴"作为完整副本,而是保留"参考"到(def foo..),原来的foo地图只被序列化一次。

  1. 我会考虑的一种技术虽然不一定鼓励(并且只有在耗尽其他选项之后,例如Frank C.暗示的数据结构的重新设置) ),是序列化bunny代码而不是结构本身。然后你读回代码字符串和eval它。只有当bunny的结构没有改变时,或者如果它没有改变,你才可以轻松地构建一个兔子地图的字符串,其中包含作为字符串一部分的相关符号,而不是这些符号的内容。

  2. 但更好的想法是序列化你的" raw"数据结构,如地图foobar,然后在读回这些数据后构建您的bunny - 同时序列化结构但不是兔子的内容。我相信这就是弗兰克的答案。

  3. 值得注意的是,如果bunny的结构确实动态变化,并且您能够按照上面的建议创建一串符号,那么这意味着您还可以使用工具来构建如上面2中所示的兔子的表示,这将是更可取的。

    由于代码是数据,因此选项1是我们作为lisp程序员可用的灵活性类型的一个示例 - 但这并不意味着没有更好的选择。