Skip to content

Instantly share code, notes, and snippets.

@socksy
Last active December 26, 2015 22:49
Show Gist options
  • Save socksy/7225668 to your computer and use it in GitHub Desktop.
Save socksy/7225668 to your computer and use it in GitHub Desktop.
Post-order traversal with a zipper in clojure
;WARNING: this puts your entire tree in memory, so if you're using zippers
;to avoid that, do not use this.
;Also, potentially terrible clojure. I only learned this a few days ago
;couldn't find any way to do this online except for a single
;stackoverflow that didn't actually use zippers
(require '[clojure.zip :as zip])
(defn zip-down [loc]
"Zips to the bottom of the tree from this loc"
(loop [p loc]
(if (zip/branch? p)
(do (def cnext-stack (cons p cnext-stack))
(recur (zip/down p)))
p)))
;visited nodes
;remember to reset after a traversal
(def cnext-stack (list))
(defn cnext
"Basically the same as clojure.zip/next, except postorder traversal."
([loc] (cnext loc cnext-stack))
([loc stack]
(if (= :end (loc 1))
loc
(or
;branch node and visited before?
(when (and (zip/branch? loc) (nil? (some #(= loc %) stack)))
(do (def cnext-stack (cons loc stack))
(zip-down loc)))
;if sibling, go to it and zip down
(when (zip/right loc) (-> loc zip/right zip-down))
(if (zip/up loc)
(zip/up loc)
[(zip/node loc) :end])))))
(defn search
"Takes a zipper, and optionally a visit/edit function"
([zipper] (search zipper nil))
([zipper edit]
(do (def cnext-stack (list))
(loop [loc zipper]
(if (zip/end? loc)
(zip/root loc)
(do
(when edit (when-let [edited (edit loc)]
(zip/replace loc edited)))
(recur (cnext loc cnext-stack))))))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment