View Source Hold.Zipper.Tree (hold v0.1.0)
Zipper over a General Tree (any number of child nodes).
Intro on Zippers: https://ferd.ca/yet-another-article-on-zippers.html
Summary
Types
A thread is a list of znodes behind us in the traversal. They support being able to walk backwards the way we came.
Znodes represent levels of the tree as a Zipper List.
Functions
Goes down one level to the children of current focus.
Same as children/1 but will throw if not able to make move
Returns whether current focus has any children
Returns tree rooted at element based on predicate
function - returning nil
when no element returns true for predicate.
Returns the currently focused element of the tree.
Adds a new node at the current focus with value
.
Adds a new child node to the current focus with value
.
Adds a new node to the right of current focus with value
.
Moves focus to the left of the current level
Same as left/1 but will throw if not able to make move
Returns whether a left siblings exists
Creates an iterator over a tree walking over all of the elements until completion.
Moves up to direct parent of current focus leaving current siblings intact.
Same as parent/1 but will throw if not able to make move
Moves focus to the right of the current level
Same as right/1 but will throw if not able to make move
Returns whether a right sibling exists.
Creates a new tree with value
placed as root.
Returns whether current focus is the root node
Moves up to parent similar to parent/1, but also resets current level
Same as rparent/1 but will throw if not able to make move
Updates the value currently at focus with value
.
Types
@type thread() :: [znode()]
A thread is a list of znodes behind us in the traversal. They support being able to walk backwards the way we came.
@type thread(a) :: [znode(a)]
@type znode() :: Hold.Zipper.List.t({term(), Hold.Zipper.List.t(znode())}) | Hold.Zipper.List.t({term(), nil})
Znodes represent levels of the tree as a Zipper List.
Given this tree:
A
↙ ↘
B C
If the focus was at B the resulting znode would be.
{ # left siblings [], # current focus | right siblings [
{
B,
nil
},
{
C,
nil
},
] }
The focus of the zipper is a 2 element tuple. The first item represents the
currently focused node. the second element represents the focused nodes
children. nil
shows that it has no children and a znode when it has them.
@type znode(a) :: Hold.Zipper.List.t({a, Hold.Zipper.List.t(znode(a))}) | Hold.Zipper.List.t({a, nil})
Functions
@spec children(t()) :: {:ok, t()} | Hold.Zipper.invalid_move()
Goes down one level to the children of current focus.
Exmaples
iex> tree = Hold.Zipper.Tree.root(0)
iex> tree = Hold.Zipper.Tree.insert_child(tree, 1)
iex> {:ok, tree} = Hold.Zipper.Tree.children(tree)
iex> Hold.Zipper.Tree.focus(tree)
1
Same as children/1 but will throw if not able to make move
Returns whether current focus has any children
Examples
iex> tree = Hold.Zipper.Tree.root(0)
iex> Hold.Zipper.Tree.children?(tree)
false
iex> tree = Hold.Zipper.Tree.root(0)
iex> tree = Hold.Zipper.Tree.insert_child(tree, 1)
iex> Hold.Zipper.Tree.children?(tree)
true
Returns tree rooted at element based on predicate
function - returning nil
when no element returns true for predicate.
The predicate
function will be invoked with the tree at the position of the
current element and the current element. The tree argument can be used if
there is a need to look at surrounding elements of the current focus in order
for the predicate
to make a decision.
Returns the currently focused element of the tree.
Examples
iex> tree = Hold.Zipper.Tree.root(0)
iex> Hold.Zipper.Tree.focus(tree)
0
iex> tree = Hold.Zipper.Tree.root(0)
iex> tree = Hold.Zipper.Tree.insert_child(tree, 1)
iex> tree = Hold.Zipper.Tree.children!(tree)
iex> Hold.Zipper.Tree.focus(tree)
1
Adds a new node at the current focus with value
.
Examples
Inserted value becomes focus
iex> tree = Hold.Zipper.Tree.root(0)
iex> tree = Hold.Zipper.Tree.insert_child(tree, 1)
iex> tree = Hold.Zipper.Tree.children!(tree)
iex> tree = Hold.Zipper.Tree.insert(tree, 2)
iex> Hold.Zipper.Tree.focus(tree)
2
Old focus is now the right sibling
iex> tree = Hold.Zipper.Tree.root(0)
iex> tree = Hold.Zipper.Tree.insert_child(tree, 1)
iex> tree = Hold.Zipper.Tree.children!(tree)
iex> tree = Hold.Zipper.Tree.insert(tree, 2)
iex> tree = Hold.Zipper.Tree.right!(tree)
iex> Hold.Zipper.Tree.focus(tree)
1
Adds a new child node to the current focus with value
.
If the parent were to then move into the child collection they would be focused on the new child.
Examples
Focus stays at parent.
iex> tree = Hold.Zipper.Tree.root(0)
iex> tree = Hold.Zipper.Tree.insert_child(tree, 1)
iex> Hold.Zipper.Tree.focus(tree)
0
Child is inserted.
iex> tree = Hold.Zipper.Tree.root(0)
iex> tree = Hold.Zipper.Tree.insert_child(tree, 1)
iex> tree = Hold.Zipper.Tree.children!(tree)
iex> Hold.Zipper.Tree.focus(tree)
1
Child goes to the head of the right sibling list.
iex> tree = Hold.Zipper.Tree.root(0)
iex> tree = Hold.Zipper.Tree.insert_child(tree, 2)
iex> tree = Hold.Zipper.Tree.children!(tree)
iex> tree = Hold.Zipper.Tree.right!(tree) # Now 2 is in left siblings
iex> tree = Hold.Zipper.Tree.parent!(tree)
iex> tree = Hold.Zipper.Tree.insert_child(tree, 1)
iex> tree = Hold.Zipper.Tree.children!(tree)
iex> tree = Hold.Zipper.Tree.left!(tree)
iex> Hold.Zipper.Tree.focus(tree)
2
Adds a new node to the right of current focus with value
.
Does not shift focus to new node.
Examples
iex> tree = Hold.Zipper.Tree.root(0)
iex> tree = Hold.Zipper.Tree.insert_child(tree, 1)
iex> tree = Hold.Zipper.Tree.children!(tree)
iex> tree = Hold.Zipper.Tree.insert_right(tree, 2)
iex> Hold.Zipper.Tree.focus(tree)
1
iex> tree = Hold.Zipper.Tree.root(0)
iex> tree = Hold.Zipper.Tree.insert_child(tree, 1)
iex> tree = Hold.Zipper.Tree.children!(tree)
iex> tree = Hold.Zipper.Tree.insert_right(tree, 2)
iex> tree = Hold.Zipper.Tree.right!(tree)
iex> Hold.Zipper.Tree.focus(tree)
2
Examples
@spec left(t()) :: {:ok, t()} | Hold.Zipper.invalid_move()
Moves focus to the left of the current level
Examples
iex> tree = Hold.Zipper.Tree.root(0)
iex> tree = Hold.Zipper.Tree.insert_child(tree, 2)
iex> tree = Hold.Zipper.Tree.insert_child(tree, 1)
iex> tree = Hold.Zipper.Tree.children!(tree)
iex> tree = Hold.Zipper.Tree.right!(tree)
iex> {:ok, tree} = Hold.Zipper.Tree.left(tree)
iex> Hold.Zipper.Tree.focus(tree)
1
Same as left/1 but will throw if not able to make move
Returns whether a left siblings exists
Examples
iex> tree = Hold.Zipper.Tree.root(0)
iex> tree = Hold.Zipper.Tree.insert_child(tree, 1)
iex> tree = Hold.Zipper.Tree.children!(tree)
iex> Hold.Zipper.Tree.left?(tree)
false
iex> tree = Hold.Zipper.Tree.root(0)
iex> tree = Hold.Zipper.Tree.insert_child(tree, 2)
iex> tree = Hold.Zipper.Tree.insert_child(tree, 1)
iex> tree = Hold.Zipper.Tree.children!(tree)
iex> tree = Hold.Zipper.Tree.right!(tree)
iex> Hold.Zipper.Tree.left?(tree)
true
Creates an iterator over a tree walking over all of the elements until completion.
Each iteration will return {:ok, item, new_tree}
until the tree has been
fully visited. At which point {:complete, last_item, new_tree}
will be
returned
@spec parent(t()) :: {:ok, t()} | Hold.Zipper.invalid_move()
Moves up to direct parent of current focus leaving current siblings intact.
The current level siblings list will not be reset before moving up. For example if you were on the second sibling of the current level moving up with parent/1 and then calling children/1 would move you back down to the second sibling again.
Examples
iex> tree = Hold.Zipper.Tree.root(0)
iex> tree = Hold.Zipper.Tree.insert_child(tree, 1)
iex> tree = Hold.Zipper.Tree.children!(tree)
iex> {:ok, tree} = Hold.Zipper.Tree.parent(tree)
iex> Hold.Zipper.Tree.focus(tree)
0
Moving to parent doesn't reset left and right sibling list.
iex> tree = Hold.Zipper.Tree.root(0)
iex> tree = Hold.Zipper.Tree.insert_child(tree, 2)
iex> tree = Hold.Zipper.Tree.insert_child(tree, 1)
iex> tree = Hold.Zipper.Tree.children!(tree)
iex> tree = Hold.Zipper.Tree.right!(tree) # 1 is now in left sibling list
iex> {:ok, tree} = Hold.Zipper.Tree.parent(tree)
iex> tree = Hold.Zipper.Tree.children!(tree)
iex> Hold.Zipper.Tree.focus(tree)
2
Same as parent/1 but will throw if not able to make move
@spec right(t()) :: {:ok, t()} | Hold.Zipper.invalid_move()
Moves focus to the right of the current level
Examples
iex> tree = Hold.Zipper.Tree.root(0)
iex> tree = Hold.Zipper.Tree.insert_child(tree, 2)
iex> tree = Hold.Zipper.Tree.insert_child(tree, 1)
iex> tree = Hold.Zipper.Tree.children!(tree)
iex> {:ok, tree} = Hold.Zipper.Tree.right(tree)
iex> Hold.Zipper.Tree.focus(tree)
2
Same as right/1 but will throw if not able to make move
Returns whether a right sibling exists.
Examples
iex> tree = Hold.Zipper.Tree.root(0)
iex> tree = Hold.Zipper.Tree.insert_child(tree, 1)
iex> tree = Hold.Zipper.Tree.children!(tree)
iex> Hold.Zipper.Tree.right?(tree)
false
iex> tree = Hold.Zipper.Tree.root(0)
iex> tree = Hold.Zipper.Tree.insert_child(tree, 2)
iex> tree = Hold.Zipper.Tree.insert_child(tree, 1)
iex> tree = Hold.Zipper.Tree.children!(tree)
iex> Hold.Zipper.Tree.right?(tree)
true
Creates a new tree with value
placed as root.
Examples
iex> tree = Hold.Zipper.Tree.root(0)
iex> Hold.Zipper.Tree.focus(tree)
0
Returns whether current focus is the root node
Examples
iex> tree = Hold.Zipper.Tree.root(0)
iex> Hold.Zipper.Tree.root?(tree)
true
iex> tree = Hold.Zipper.Tree.root(0)
iex> tree = Hold.Zipper.Tree.insert_child(tree, 1)
iex> tree = Hold.Zipper.Tree.children!(tree)
iex> Hold.Zipper.Tree.root?(tree)
false
@spec rparent(t()) :: {:ok, t()} | Hold.Zipper.invalid_move()
Moves up to parent similar to parent/1, but also resets current level
If for example you were on the second sibling of the current level moivng up with rparent/1 and then calling children/1 would move you back down to first sibling instead of the second.
Examples
iex> tree = Hold.Zipper.Tree.root(0)
iex> tree = Hold.Zipper.Tree.insert_child(tree, 1)
iex> tree = Hold.Zipper.Tree.children!(tree)
iex> {:ok, tree} = Hold.Zipper.Tree.parent(tree)
iex> Hold.Zipper.Tree.focus(tree)
0
Unlike parent/1
the left and right sibling list is reset
iex> tree = Hold.Zipper.Tree.root(0)
iex> tree = Hold.Zipper.Tree.insert_child(tree, 2)
iex> tree = Hold.Zipper.Tree.insert_child(tree, 1)
iex> tree = Hold.Zipper.Tree.children!(tree)
iex> tree = Hold.Zipper.Tree.right!(tree) # 1 is now in left sibling list
iex> {:ok, tree} = Hold.Zipper.Tree.rparent(tree) # This resets sibling list
iex> tree = Hold.Zipper.Tree.children!(tree)
iex> Hold.Zipper.Tree.focus(tree)
1
Same as rparent/1 but will throw if not able to make move
Updates the value currently at focus with value
.
The new value at node will keep the children present in the old node.
Examples
Update the current focus.
iex> tree = Hold.Zipper.Tree.root(0)
iex> tree = Hold.Zipper.Tree.insert_child(tree, 1)
iex> tree = Hold.Zipper.Tree.update(tree, 0.5)
iex> Hold.Zipper.Tree.focus(tree)
0.5
Children of the updated node do not change.
iex> tree = Hold.Zipper.Tree.root(0)
iex> tree = Hold.Zipper.Tree.insert_child(tree, 1)
iex> tree = Hold.Zipper.Tree.update(tree, 0.5)
iex> tree = Hold.Zipper.Tree.children!(tree)
iex> Hold.Zipper.Tree.focus(tree)
1