Skip to content

Instantly share code, notes, and snippets.

@renegr
Created March 11, 2014 20:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save renegr/9493967 to your computer and use it in GitHub Desktop.
Save renegr/9493967 to your computer and use it in GitHub Desktop.
Functional Zippers
(ns tree
(:require [clojure.zip :as zip]))
(defn make-zip
"Returns a zipper for a given datastructure"
[root]
(zip/zipper (complement string?)
(comp seq :children)
(fn [node children]
(assoc node :children children))
root))
(defn find-by-id
"Finds an element by it's id.
Returns a vector [element zip-loc]."
[root id]
(loop [loc (make-zip root)]
(let [found? (when (= (-> loc zip/node :id) id) (zip/node loc))]
(if (or (zip/end? loc) found?)
(if found? [found? loc] nil)
(recur (zip/next loc))))))
(defn transact!
"Finds <id> then applies <f> to node & returns the updated tree."
[root id f]
(if-let [[elm loc] (find-by-id root id)]
(-> (zip/edit loc f) zip/root)
root))
(comment
"Usage Example:"
(def sample {:name "A"
:id 1
:children [{:name "B"
:id 2
:children []}
{:name "C"
:id 3
:children [{:name "D" :id 4 :children []}]}]})
(transact! sample 2 #(assoc % :name "Z")))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment