A Clojure library providing zippers for labeled unordered trees, such as nested maps.
This library is modeled after clojure.zip
, with the set of navigators
slightly adjusted.
The coordinates of the library:
[mg.dt/azip "0.1.0"]
The namespace of the library:
(require '[mg.dt.azip :as azip])
Given a nested map structure
user=> (def data {:child-a {:leaf-a "a" :leaf-b "b"} :child-b {}})
#'user/data
create a zipper using map-azip
(generic azipper
is available too)
user=> (def rootz (azip/map-azip data))
#'user/rootz
Navigators for moving the zipper are called down
and up
user=> (def childz (azip/down rootz :child-a))
#'user/childz
user=> (def leafz (azip/down childz :leaf-a))
#'user/leafz
user=> (= (azip/up leafz) childz)
true
You can use branch?
, node
, children
, down?
to interrogate the state of
zipper
user=> (azip/branch? childz)
true
user=> (azip/branch? leafz)
false
user=> (azip/node rootz)
{:child-a {:leaf-a "a", :leaf-b "b"}, :child-b {}}
user=> (azip/node childz)
{:leaf-a "a", :leaf-b "b"}
user=> (azip/children rootz)
(:child-a :child-b)
user=> (azip/down? rootz :child-a)
true
user=> (azip/down? rootz :missing)
false
insert
adds a new child at the current position of the zipper, replacing
existing child if it exists
user=> (-> rootz (azip/insert :newkey :newval)
(azip/node))
{:child-a {:leaf-a "a", :leaf-b "b"}, :child-b {}, :newkey :newval}
user=> (-> rootz (azip/insert :child-a :newval)
(azip/node))
{:child-a :newval, :child-b {}}
replace
and edit
change the current node
user=> (-> childz (azip/replace :rep)
(azip/up)
(azip/node))
{:child-a :rep, :child-b {}}
user=> (-> leafz (azip/edit (fn [node arg] arg) :rep)
(azip/up)
(azip/up)
(azip/node))
{:child-a {:leaf-a :rep, :leaf-b "b"}, :child-b {}}
root
is a shortcut to move the zipper to the top and return the whole data
structure
user=> (-> leafz (azip/replace :rep) (azip/root))
{:child-a {:leaf-a :rep, :leaf-b "b"} :child-b {}}
Copyright © 2017 Mikhail Gusarov dottedmag@dottedmag.net
Distributed under the MIT license.