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

Serialization 在clojure中序列化持久数据结构,serialization,clojure,Serialization,Clojure,我们都知道,Rich使用了一种理想的基于哈希树的方法来实现Clojure中的持久数据结构。这种结构使我们能够在不进行大量复制的情况下操作持久数据结构 但我似乎找不到序列化这个特定结构的正确方法。例如: (def foo {:a :b :c :d}) (def bar (assoc foo :e :f)) (def bunny {:foo foo :bar bar}) 我的问题是: 我如何序列化小兔子,使foo的内容,即:a映射到:b和:c映射到:d的内容在序列化内容中只出现一次?这就像是在倾倒

我们都知道,Rich使用了一种理想的基于哈希树的方法来实现Clojure中的持久数据结构。这种结构使我们能够在不进行大量复制的情况下操作持久数据结构

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

(def foo {:a :b :c :d})
(def bar (assoc foo :e :f))
(def bunny {:foo foo :bar bar})
我的问题是:

我如何序列化
小兔子
,使
foo
的内容,即
:a
映射到
:b
:c
映射到
:d
的内容在序列化内容中只出现一次?这就像是在倾倒建筑物的记忆图像。这也类似于序列化引用的“内部节点”和“叶节点”

p.S.如果这是相关的,我正在构建一个大的DAG(有向无环图),在这里我们
assoc
相当多地将这些节点链接到这些节点,并希望序列化DAG以便以后反序列化。图形的扩展表示(即在repl中打印DAG时将获得的内容)太长,令人无法接受。

Davyzhu

首先是几件事:

  • 没有标记化策略的DAG将与DAG一样长。如果
    foo
    被引用1次或多次,则在打印过程中,每一次都将被完全实现(即显示)
  • 对于信息交换(序列化和反序列化),这在很大程度上取决于您的目标。例如,如果您正在序列化以通过线路发送数据,则您可能希望完全执行(如打印的表示),或者需要使用某种标识/标记化策略对单个数据点进行编码。当然,后者假设接收端可以在理解令牌化协议的情况下进行反序列化
  • 标记化策略示例可能使用Clojure工具,需要为每个内容块引用编码唯一的键,并且DAG包含节点,其中边由键表示
  • 编辑::从原始帖子开始修改,以根据评论进行澄清,但示例 不反映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取决于您。

    这是一个选项(在Clojurescript中不起作用,以防出现问题),通常可能会被视为一个坏主意,但无论如何都值得一提

    如果我理解您的问题,您希望
    (def bunny{:foo foo:bar bar})中的
    foo
    不被“粘贴”为完整副本,而是保留对
    (def foo..)
    的“引用”,以便原始
    foo
    映射只序列化一次

    <> LI>

    一种技术,我认为虽然不一定会鼓励(并且在耗尽了其他选项,比如Frank C.的数据结构的重新组织化)之后,将序列化代码<代码> Bunn,而不是结构本身。然后将代码字符串读回并

    eval
    it。只有在bunny的结构没有改变的情况下,或者如果它改变了,您可以轻松地构建一个包含相关符号(而不是这些符号的内容)的bunny地图字符串,这才有效

  • 但更好的方法是只序列化“原始”数据结构,如映射
    foo
    bar
    ,然后在读回这些数据结构后构建
    bunny
    ——也序列化结构,但不序列化bunny的内容。我相信这就是弗兰克的答案

  • 值得注意的是,如果bunny的结构确实是动态变化的,那么您可以按照1中的建议创建一组符号。在上面,这意味着您还可以使用工具来构建bunny的表示,如图2所示。以上,这将是更好的


    因为代码是数据,所以选择1。作为lisp程序员,我们可以使用这种灵活性的一个例子,但这并不意味着没有更好的选项。

    您是指键
    :a
    :c
    及其相应的值?还是仅仅是
    :a
    :b
    的元素?@cfrick感谢您的编辑。
    foo
    的全部内容应该在构建
    bar
    时重用,我希望序列化只包含一次
    foo
    的内容。我将再次编辑这个问题以澄清问题。如果您还可以指定您的期望值-bunny的序列化结果应该是什么样的,那就太好了。对我来说(strbunny)的结果是{:foo{:c:d,:a:b},:bar{:e:f,:c:d,:a:b},这似乎是正确的。但我不明白你说的是什么意思“只包含一次foo的内容。@ViktorK。我不特定于任何实现,只要我不必完全实现DAG。正如@Frank在下面的回答中所说的,我希望能够实现自动标记化,就像用于实现
    PersistentMap
    PersistentVector
    的标记化一样。您能再次检查您设计的示例吗?我觉得有点难以理解。为什么
    [:node foo]
    会在其中出现两次?我们使用源节点表示DAG,其余节点间接引用。此外,你是说我必须自己实现标记化协议,即使这已经在幕后完成了吗?Davyzhu:希望编辑有帮助,我将更多的内容映射到你的示例中,以反映DAG的一些结构。我使用向量是基于我对本体的经验。我明白了。您将展示如何标记图形并区分标记和内容。我将尝试遍历图形,并执行此操作。谢谢hellofunk:我也在想类似的事情。在最近的编辑中,我添加了一个“字典”,在现实世界中,它将由一个atom来管理,这是最有效的。这很有趣!但是