Clojure对异构树的Zipper

3

我遇到了编写能够遍历异构节点树的zipper的问题。我有i)一组映射列表,每个映射都有ii)一个:inputs键,其值是映射列表。

我想使用zipper访问每个叶子并添加计算出的值。以下是代码块和输入树数据。我似乎无法使zipper代码访问叶子节点并添加{ :thing 123 }。我肯定是漏掉了某些简单的东西。有任何建议吗?

A)

      (loop [loc (zip/zipper  (or map? list?)
                              #((if (map? %1)              ;; 获取节点的子项
                                  (:inputs %1)
                                  %1 ))
                              #(%1)                            ;; 创建新节点
                              (:input-layer neural-network)) ]
(if (zip/end? loc) (zip/root loc) (if (map? loc) (recur (zip/next (zip/edit loc merge { :thing 123 } ))) (recur (zip/next loc)) ) ) )

B)

     ({:inputs
       ({:key :avolume, :value 2.25, :weight 0.4283380545172636, :bias 0}
        {:key :bvolume, :value 3.0, :weight 0.6970037374879661, :bias 0}
        {:key :ask, :value 1.32379, :weight 0.5387437158323669, :bias 0}
        {:key :bid, :value 1.3239, :weight 0.4648184032361037, :bias 0}
        {:key :time, :value 1.335902400676, :weight 0.43632873607404554, :bias 0}),
       :id "583c10bfdbd326ba34aed329139df6be2487ffc"})
      ({:inputs
       ({:key :avolume, :value 2.25, :weight 0.13162215440222336, :bias 0}
        {:key :bvolume, :value 3.0, :weight 0.23886901184352727, :bias 0}
        {:key :ask, :value 1.32379, :weight 0.8408470512339872, :bias 0}
        {:key :bid, :value 1.3239, :weight 0.27071013797961796, :bias 0}
        {:key :time, :value 1.335902400676, :weight 0.6304505838898373, :bias 0}),
       :id "583c10bfdbd326ba34aed329139df6be2487ffd"})
      ({:inputs
       ({:key :avolume, :value 2.25, :weight 0.8236972641966921, :bias 0}
        {:key :bvolume, :value 3.0, :weight 0.32421537754016705, :bias 0}
        {:key :ask, :value 1.32379, :weight 0.966306328543246, :bias 0}
        {:key :bid, :value 1.3239, :weight 0.8891668220470931, :bias 0}
        {:key :time, :value 1.335902400676, :weight 0.278993745549462, :bias 0}),
       :id "583c10bfdbd326ba34aed329139df6be2487ffe"})
      ({:inputs
       ({:key :avolume, :value 2.25, :weight 0.27388486254027167, :bias 0}
        {:key :bvolume, :value 3.0, :weight 0.33659579299487363, :bias 0}
        {:key :ask, :value 1.32379, :weight 0.16610378593177033, :bias 0}
        {:key :bid, :value 1.3239, :weight 0.6964784902474896, :bias 0}
        {:key :time, :value 1.335902400676, :weight 0.6306732906337643, :bias 0}),
       :id "583c10bfdbd326ba34aed329139df6be2487fff"})
      ({:inputs
       ({:key :avolume, :value 2.25, :weight 0.8819171698935051, :bias 0}
        {:key :bvolume, :value 3.0, :weight 0.5944805362120958, :bias 0}
        {:key :ask, :value 1.32379, :weight 0.9060962647355373, :bias 0}
        {:key :bid, :value 1.3239, :weight 0.37647418075176464, :bias 0}
        {:key :time, :value 1.335902400676, :weight 0.7797681719480866, :bias 0}),
       :id "583c10bfdbd326ba34aed329139df6be2488000"})
感谢您使用我们的服务。
1个回答

5
我认为创建新节点的部分是错误的。如果您阅读 zipper函数的定义,您会发现`make-node`被调用时带有2个参数:当前节点和新子节点的序列。该函数应返回新节点。
您使用的表达式`#(%1)`根本不起作用,因为您正在尝试将map或list作为函数调用。
同时,表达式`(or map? list?)`并不是您想要的。
我为向量进行了适配,只是为了测试。
(defn mk-zip [root]
  (let [branch? (fn [node]
                  (when node
                    (or (and (map? node) (contains? node :inputs))
                        (vector? node))))
        children (fn [node]
                   (cond 
                     (nil? node) nil
                     (map? node) (:inputs node)
                     :else node))
        make-node (fn [node children]
                    (cond
                      (nil? node) nil
                      (map? node) (assoc node :inputs children)
                      (vector? node) (into [] children)
                      :else node))]
    (zip/zipper branch? children make-node root)))
(def root [{:inputs [{:key :avolume, :value 2.25, :weight 0.4283380545172636, :bias 0} {:key :bvolume, :value 3.0, :weight 0.6970037374879661, :bias 0} {:key :ask, :value 1.32379, :weight 0.5387437158323669, :bias 0} {:key :bid, :value 1.3239, :weight 0.4648184032361037, :bias 0} {:key :time, :value 1.335902400676, :weight 0.43632873607404554, :bias 0}], :id "583c10bfdbd326ba34aed329139df6be2487ffc"}])
现在可以更新map中的项:
(def z (mk-zip root))
(-> z zip/next zip/down 
    (zip/insert-right {:key :new :value -10}) 
    zip/up
    zip/node)

输出:

{:inputs
 ({:key :avolume, :weight 0.4283380545172636, :bias 0, :value 2.25}
  {:key :new, :value -10}
  {:key :bvolume, :weight 0.6970037374879661, :bias 0, :value 3.0}
  {:key :ask, :weight 0.5387437158323669, :bias 0, :value 1.32379}
  {:key :bid, :weight 0.4648184032361037, :bias 0, :value 1.3239}
  {:key :time,
   :weight 0.43632873607404554,
   :bias 0,
   :value 1.335902400676}),
 :id "583c10bfdbd326ba34aed329139df6be2487ffc"}

1
太棒了。原来是这样,我在遍历树时对拉链的位置和节点感到困惑。谢谢朋友。 - Nutritioustim

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接