Clojure-使用Spectre转换嵌套的数据结构,用几个替换一个节点

Tom*_*mSW 6 tree transform clojure specter

我正在使用spectre转换Clojure中的嵌套数据结构,但还没有掌握。特别是,我正在尝试创建一个转换,该转换将找到一个与谓词匹配的项(无论深度如何),并将其替换为多个项。

[:top
 [:arbitrary 1 2
  [:nesting
   2
   3
   [:needle] ; <-- the thing to find
   ]]]

-->

[:top
 [:arbitrary 1 2
  [:nesting
   2
   3
   [:n1] [:n2] [:n3]  ; <-- 3 items inserted in the place of 1
   ]]]
Run Code Online (Sandbox Code Playgroud)

我不知道的是如何将替换项拼接到父向量中,即,如何用三个项替换一个项,而不是用包含三个子项的一项替换。

Tay*_*ood 3

我不知道如何使用 Spectre 执行此操作,但这里有一个使用 clojure.zip 执行此操作的函数:

(defn splice-replace [zipper smap]
  (loop [loc zipper]
    (if (z/end? loc)
      (z/root loc)
      (recur
       (z/next
        (if-let [sub (smap (z/node loc))]
          (reduce (comp z/right z/insert-right)
                  (z/replace loc (first sub))
                  (rest sub))
          loc))))))
Run Code Online (Sandbox Code Playgroud)

您可以使用数据结构的拉链和从要替换的值到要拼接到其位置的替换值序列的映射来调用它:

(def zipper
  (z/vector-zip [:top
                 [:arbitrary 1 2
                  [:nesting 2 3 [:needle]]]]))

(splice-replace zipper {[:needle] [[:n1] [:n2] [:n3]]})
 => [:top [:arbitrary 1 2 [:nesting 2 3 [:n1] [:n2] [:n3]]]]

(splice-replace zipper {[:nesting 2 3 [:needle]] (range 3 10)})
=> [:top [:arbitrary 1 2 3 4 5 6 7 8 9]]
Run Code Online (Sandbox Code Playgroud)