首页 > 解决方案 > Clojure - 使用 Spectre 转换嵌套数据结构,将一个节点替换为多个

问题描述

我正在使用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
   ]]]

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

标签: clojuretreetransformspecter

解决方案


我不知道如何使用 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))))))

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

(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]]

推荐阅读