A generic Rose Tree.
Note: This library is designed to work with unique values attached to tree nodes. This is usually achievable using records having a unique id, though unicity checks should be performed by consumers of this library.
Append a new value to a Node identified by its value in a Tree.
node "foo" [ leaf "bar"]
|> append "foo" "baz"
--> node "foo" [ leaf "bar", leaf "baz" ]Prepend a new value to a Node identified by its value in a Tree.
node "foo" [ leaf "bar"]
|> prepend "foo" "baz"
--> node "foo" [ leaf "baz", leaf "bar" ]Deletes all occurrences of a value from a tree.
node "root" [ node "foo" [ leaf "bar" ] ]
|> remove "bar"
--> node "root" [ leaf "foo" ]Noop when the value doesn't exist in the tree:
node "root" [ leaf "foo" ]
|> remove "non-existent"
--> node "root" [ leaf "foo" ]Or when attempting to delete the tree itself:
leaf "root"
|> remove "root"
--> leaf "root"Seed a tree.
seed (\x -> List.range 1 (x - 1)) 4
--> node 4
--> [ leaf 1
--> , node 2 [ leaf 1 ]
--> , node 3
--> [ leaf 1
--> , node 2 [ leaf 1 ]
--> ]
--> ]List all the values in a tree.
node 1 [ node 2 [ leaf 3 ] ]
|> values
--> [ 1, 2, 3 ]Extracts the children of a Node.
node "foo" [ leaf "bar" ]
|> children
--> [ leaf "bar" ]Get a Node holding a value from a tree, picking the first node found starting from the left.
node "root" [ leaf "bar" ]
|> get "bar"
--> Just (leaf "bar")Get all nodes containing the provided value.
node 1 [ leaf 1 ]
|> getAll 1
--> [ node 1 [ leaf 1 ], leaf 1 ]Retrieve all leaves (singletons) from a tree.
node "root"
[ leaf "a leaf"
, node "branch"
[ leaf "another leaf" ]
]
|> leaves
--> [ "a leaf", "another leaf" ]Retrieve all nodes at a given level in the tree.
node "root"
[ node "1" [ node "1.1" [ leaf "1.1.1" ] ]
, node "2" [ node "2.1" [ leaf "2.1.1" ] ]
]
|> level 3
--> [ leaf "1.1.1"
--> , leaf "2.1.1"
--> ]
node "root"
[ node "1" [ node "1.1" [ leaf "1.1.1" ] ]
, node "2" [ node "2.1" [ leaf "2.1.1" ] ]
]
|> level 2
--> [ node "1.1" [ leaf "1.1.1" ]
--> , node "2.1" [ leaf "2.1.1" ]
--> ]Compute the maximum value appearing in a tree.
node 1 [ leaf 100, node 2 [ leaf 3 ] ]
|> maximum
--> 100Compute the minimum value appearing in a tree.
node 100 [ leaf 99, node 1 [ leaf 98 ] ]
|> minimum
--> 1Retrieve the parent of a given node in a Tree, identified by its value.
node "root" [ node "foo" [ leaf "bar" ] ]
|> parent "bar"
--> Just (node "foo" [ leaf "bar" ])Compute the path to a the first node holding the target value, from the root.
node "root"
[ leaf "qux"
, node "foo"
[ node "bar"
[ leaf "baz" ]
]
]
|> path "baz"
|> List.map value
--> [ "root", "foo", "bar", "baz" ]Retrieve all values from nodes containing those satisfying a provided condition.
node 1 [ node 2 [ leaf 3, leaf 4, leaf 5 ] ]
|> seek (\x -> x > 3)
--> [ leaf 4, leaf 5 ]Retrieve siblings of a node identified by its value in a Tree.
node "foo" [ leaf "a", node "b" [ leaf "x" ], leaf "c" ]
|> siblings "c"
--> [ leaf "a", node "b" [ leaf "x" ] ]Check that all values satisfy a test in a tree.
node 1 [ leaf 2 ]
|> all (\x -> x > 0)
--> True
node 1 [leaf -2]
|> all (\x -> x > 0)
--> FalseCheck that any value satisfy a test in a tree.
node 1 [ leaf -2 ]
|> any (\x -> x > 0)
--> True
node -1 [ leaf -2 ]
|> any (\x -> x > 0)
--> FalseCheck if a tree contains a value.
node "foo" [ node "bar" [ leaf "baz" ] ]
|> member "baz"
--> True
leaf "no"
|> member "yes"
--> FalseMap a Node's children.
node "root" [ leaf "foo", leaf "bar" ]
|> mapChildren (map String.toUpper)
--> node "root" [ leaf "FOO", leaf "BAR" ]Replace the children of a Node.
Replace the value of a Node.
Update a Node value using an update function. This is especially useful for updating record properties.
leaf { name = "root" }
|> updateValue (\r -> { r | name = r.name ++ "!"})
--> leaf { name = "root!" }Map a targetted Node's children in a tree.
node 1 [ node 2 [ leaf 3, leaf 4 ] ]
|> mapChildrenAt 2 (updateValue ((*) 2))
--> node 1 [ node 2 [ leaf 6, leaf 8 ] ]Replace all Nodes holding a given value with a new Node in a Tree.
node "root" [ node "foo" [ leaf "bar" ] ]
|> replaceAt "foo" (leaf "bar")
--> node "root" [ leaf "bar" ]
node "root" [ leaf "foo", leaf "foo" ]
|> replaceAt "foo" (leaf "bar")
--> node "root" [ leaf "bar", leaf "bar" ]Replace a targetted Node's children in a tree.
node 1 [ node 2 [ leaf 3, leaf 4 ] ]
|> replaceChildrenAt 2 [ leaf 5 ]
--> node 1 [ node 2 [ leaf 5 ] ]Replace a targetted Node value with another one in a Tree.
node "root" [ node "foo" [ leaf "bar" ] ]
|> replaceValueAt "foo" "baz"
--> node "root" [ node "baz" [ leaf "bar" ] ]
node "root" [ leaf "foo", leaf "foo" ]
|> replaceValueAt "foo" "bar"
--> node "root" [ leaf "bar", leaf "bar" ]Update a targetted Node in a tree, using an update function.
node 1 [ node 2 [ leaf 3 ] ]
|> updateAt 3 (always (leaf 42))
--> node 1 [ node 2 [ leaf 42 ] ]Update a targetted Node value in a tree, using an update function.
node 1 [ node 2 [ leaf 3 ] ]
|> updateValueAt 3 ((*) 2)
--> node 1 [ node 2 [ leaf 6 ] ]Filter a Tree strictly, removing all nodes failing the provided value test, including root, hence the resulting Maybe.
node 0 [ leaf 1 ]
|> filter (\x -> x > 0)
--> Nothing
node 2 [ leaf 3, leaf 4 ]
|> filter (\x -> modBy 2 x == 0)
--> Just (node 2 [ leaf 4 ])Map each node using a mapping function then flatten the result into a new list.
node "foo" [ node "bar" [ leaf "baz" ] ]
|> flatMap (value >> String.toUpper)
--> [ "FOO", "BAR", "BAZ" ]Flatten a Tree, from top to bottom and leftmost nodes to rightmost ones.
node "root" [ node "foo" [ leaf "bar", leaf "baz" ] ]
|> flatten
--> [ node "root" [ node "foo" [ leaf "bar", leaf "baz" ] ]
--> , node "foo" [ leaf "bar", leaf "baz" ]
--> , leaf "bar"
--> , leaf "baz"
--> ]Reduce all tree values from top to bottom, left to right.
node 1 [ node 2 [ leaf 3 ] ]
|> foldl (+) 0
--> 6
node "a"
[ node "b" [ leaf "c" ]
, node "d" [ node "e" [ leaf "f" ] ]
, leaf "g"
]
|> foldl (\value acc -> acc ++ value) ""
--> "abcdefg"Reduce all tree values from top to bottom, right to left.
node "a"
[ node "b" [ leaf "c" ]
, node "d" [ node "e" [ leaf "f" ] ]
, leaf "g"
]
|> foldr (\value acc -> acc ++ value) ""
--> "gfedcba"Map all Node values in a Tree.
node "root" [ leaf "foo", node "bar" [ leaf "baz" ] ]
|> map String.toUpper
--> node "ROOT" [ leaf "FOO", node "BAR" [ leaf "BAZ" ] ]Filter a Tree, keeping only nodes which attached leaves satisfy the provided test and preserving their ancestors, up to the tree root, which is always kept.
node 2
[ node 4
[ leaf 6
, leaf 7
, node 8
[ leaf 10
, leaf 11
, leaf 12
, leaf 13
]
]
]
|> refine (\x -> modBy 2 x == 0)
--> node 2
--> [ node 4
--> [ leaf 6
--> , node 8
--> [ leaf 10
--> , leaf 12
--> ]
--> ]
--> ]Recursively sort node children from a tree using a sorter.
node 0 [ leaf 3, leaf 1, leaf 2 ]
|> sortBy identity
--> node 0 [ leaf 1, leaf 2, leaf 3 ]Recursively sort node children from a tree using a comparator.
node 0 [ leaf 3, leaf 1, leaf 2 ]
|> sortWith (\a b -> if a == b then EQ else if a < b then GT else LT)
--> node 0 [ leaf 3, leaf 2, leaf 1 ]Turn a Node into a tuple containing the value and the parent value, if any.
Build a tree from a list of hierarchy descriptors, which are tuples of value and parent value, starting with the root.
[ ( "root", Nothing )
, ( "foo", Just "root" )
, ( "bar", Just "foo" )
]
|> fromList
--> Just (node "root" [ node "foo" [ leaf "bar" ] ])Turn a tree of node into a list of tuples.
node "root" [ node "foo" [ leaf "bar" ], leaf "baz" ]
|> toList
--> [ ( "root", Nothing )
--> , ( "foo", Just "root")
--> , ( "bar", Just "foo")
--> , ( "baz", Just "root")
--> ]A JSON Node decoder. You must specify a decoder for values.
import Json.Decode as Decode
json : String
json = "{\"value\":\"foo\",\"children\":[{\"value\":\"bar\",\"children\":[]}]}"
Decode.decodeString (decode Decode.string) json
--> Ok (node "foo" [ leaf "bar" ])
A Rose Tree. Each node contains a value and children, which are themselves Nodes: