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.
If I understand your objective properly I believe this will do the trick:
As a test, here is an example of printing the return from
visitedfor each step in a traversal of a relatively complex tree: