When you iterate through an arbitrarily nested Clojure zipper in a depth-first fashion via z/next, can you get or reconstruct the already visited part of the zipper, preserving its structure? For example, let's have a vector zipper of [0 [1 2] 3]. How can I implement a function visited to return the visited part of the zipper, such as [0 [1]] when visiting 1?
EDIT: Prompted by the helpful answers, I realized that a loc can be considered visited only when its subtree is completely traversed. Consequently, only non-branch locs (i.e. (complement z/branch?)) count as visited.
(require '[clojure.zip :as z]) (def zipper (z/vector-zip [0 [1 2] 3])) (defn visited [zipper] ; ... ) (-> zipper z/next visited) ; => [0] (-> zipper z/next z/next visited) ; => [0] (-> zipper z/next z/next z/next visited) ; => [0 [1]] (-> zipper z/next z/next z/next z/next visited) ; => [0 [1 2]] (-> zipper z/next z/next z/next z/next z/next visited) ; => [0 [1 2] 3] z/lefts returns only the visited part on the same hierarchical level.
EDIT 2: The answer by amalloy seems to almost work. If we make it start with into, then it works correctly for the example zipper:
(def visited (letfn [(root? [node] (= (z/node node) (z/root node)))] (fn [node] (if-let [parent (z/up node)] (let [comb-fn (if (root? parent) into conj)] (comb-fn (visited parent) (if (z/branch? node) (vec (z/lefts node)) (conj (vec (z/lefts node)) (z/node node))))) [])))) ;; we're at the root However, its limitations become apparent with more nesting. For example:
(def zipper (z/vector-zip [0 [1 [2]]])) (-> zipper z/next z/next z/next z/next z/next visited) ; => [0 [1] [2]] I wonder if z/edit can fit better.