This module provides a simple tree data type of arbitrary arity (a rose tree). There are primitives for building and traversing such a tree.
Data type representing an n-ary tree with node labels of type a
Building such a tree is done with the empty
, leaf
and inner
smart
constructors. An example for a tree with three leafs and a root node:
tree =
inner 1 [ leaf 2, leaf 3, leaf 4 ]
List (Tree label)
This is just an alias for a list of trees, called a forest in the literature.
empty : Tree label
Construct an empty tree with no nodes.
leaf : label -> Tree label
Construct a tree with a single node from a value for the node's label.
tree : Tree Int
tree =
leaf 42
inner : label -> List (Tree label) -> Tree label
Construct a new tree by inner label children
, combining a number of
subtrees children
with a label
for the new inner node which will be
the root of the tree. Empty subtrees are filtered out. An example:
tree1 = inner 1 [leaf 2, leaf 3, leaf 4]
tree2 = inner 1 [leaf 2, leaf 3, leaf 4, empty]
tree1 == tree2
unfoldTree : (seed -> ( label, List seed )) -> seed -> Tree label
Construct a new tree with unfoldTree next seed
, top to bottom. next
will be
called repeatedly with seeds, from which it should construct a label for
the current tree node but also a list of seeds from which to unfold
child nodes. This sort of works top to bottom compared to creating a
tree bottom up by using the other primitives.
tree1 = inner 1 [leaf 2, leaf 3, leaf 4]
next seed = (seed, if seed == 1 then [2, 3, 4] else [])
tree2 = unfoldTree next 1
tree1 == tree2
unfoldForest : (seed -> ( label, List seed )) -> List seed -> Forest label
Construct a new forest with unfoldForest next seeds
by unfoldTree next seed
for each seed
in seeds
. A simple specification would be
unfoldForest next seeds =
List.map (unfoldTree next) seeds
map : (a -> b) -> Tree a -> Tree b
map f tree
applies supplied function f to every label in a tree, without changing the structure of the tree
map (\x -> x + 1) empty == empty
map (\x -> x * 10) (inner 1 [ leaf 2, leaf 3 ]) == inner 10 [ leaf 20, leaf 30 ]
isEmpty : Tree label -> Basics.Bool
isEmpty tree
returns true if and only if tree
is empty
.
isEmpty empty == True
isEmpty (leaf 42) == False
root : Tree label -> Maybe ( label, Forest label )
root tree
returns Nothing
if tree
is empty
, otherwise
it returns Just (label, childForest)
of the root node.
tree = inner 1 [leaf 2, leaf 3, leaf 4]
root tree == Just (1, [leaf 2, leaf 3, leaf 4])
root empty == Nothing
size : Tree label -> Basics.Int
The size of the tree, e.g. the number of nodes.
tree = inner 0 [inner 1 [leaf 2, leaf 3], inner 4 [leaf 5, leaf 6]]
size tree == 7
height : Tree label -> Basics.Int
Computes the height of the tree in O(n) time.
tree = inner 0 [inner 1 [leaf 2, leaf 3], inner 4 [leaf 5, leaf 6]]
height tree == 3
It is instructory to read the article on tree traversals on Wikipedia first if you are not familiar with the concept.
levelOrder : (label -> Forest label -> acc -> acc) -> acc -> Tree label -> acc
levelOrder visit acc tree
is a breadth-first fold over tree
,
visiting each node and accumulating results with visit
. Nodes are visited
in level-order, e.g. for a tree like
tree =
inner 0 [ inner 1 [ leaf 2, leaf 3 ], inner 4 [ leaf 5, leaf 6 ] ]
nodes would be visited in order [0, 1, 4, 2, 3, 5, 6]
. This is in fact the
list produced by levelOrderList
, but through levelOrder
you also get access
to the children of the current node via the second parameter of visit.
levelOrderList : Tree label -> List label
See the documentation on levelOrder
. levelOrderList tree
produces
a list of the nodes of the tree visited in level-order, e.g. breadth-first.
So:
tree = inner 0 [inner 1 [leaf 2, leaf 3], inner 4 [leaf 5, leaf 6]]
levelOrderList tree == [0, 1, 4, 2, 3, 5, 6]
If you also need information on child trees instead of just the node labels,
use levelOrder
.
preOrder : (label -> Forest label -> acc -> acc) -> acc -> Tree label -> acc
preOrder visit acc tree
is a (depth-first) pre-order traversal (fold)
over tree
where visit
is called with the label and the child sub-forest of
the current node in addition to a supplied accumulator value.
Post-order traversals work top-down: When visit
is called for some node,
acc
already contains the value of all ancestral nodes.
See preOrderList
for an example on the order in which nodes are visited.
preOrderList : Tree label -> List label
See preOrder
for an explanation of how post-order traversals work.
Here is an example on visit order:
tree = inner 0 [inner 1 [leaf 2, leaf 3], inner 4 [leaf 5, leaf 6]]
preOrderList tree == [0, 1, 2, 3, 4, 5, 6]
If you also need information on child trees instead of just the node labels,
use preOrder
.
postOrder : (label -> Forest label -> acc -> acc) -> acc -> Tree label -> acc
postOrder visit acc tree
is a (depth-first) post-order traversal (fold)
over tree
where visit
is called with the label and the child sub-forest of
the current node in addition to a supplied accumulator value.
When visit
is called for some node, acc
already contains the value of all
sub-trees, so post-order traversal is a kind of bottom-up traversal, where
all children are visited prior to their parent.
See postOrderList
for an example on the order in which nodes are visited.
postOrderList : Tree label -> List label
See postOrder
for an explanation of how post-order traversals work.
Here is an example on visit order:
tree = inner 0 [inner 1 [leaf 2, leaf 3], inner 4 [leaf 5, leaf 6]]
postOrderList tree == [2, 3, 1, 5, 6, 4, 0]
If you also need information on child trees instead of just the node labels,
use postOrder
.