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.
A Rose Tree. Each node contains a value and children, which are themselves Nodes:
myTree : Tree Int
myTree =
Node 1
[ Node 2
[ Node 3 []
, Node 4 []
]
, Node 5 []
]
node : a -> List (Node a) -> Node a
Create a Node. Basically just an alias for the Node
constructor.
leaf : a -> Node a
Create a node having no children (singleton).
leaf "foo"
--> Node "foo" []
append : a -> a -> Node a -> Node a
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 -> a -> Node a -> Node a
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" ]
remove : a -> Node a -> Node a
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 -> List a) -> a -> Node a
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 ]
--> ]
--> ]
value : Node a -> a
Extract the value of a Node.
leaf 2 |> value
--> 2
values : Node a -> List a
List all the values in a tree.
node 1 [ node 2 [ leaf 3 ] ]
|> values
--> [ 1, 2, 3 ]
children : Node a -> List (Node a)
Extracts the children of a Node.
node "foo" [ leaf "bar" ]
|> children
--> [ leaf "bar" ]
length : Node a -> Basics.Int
Count nodes in a tree.
node 1 [node 2 [ node 3 [ leaf 4 ] ] ]
|> length
--> 4
get : a -> Node a -> Maybe (Node a)
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")
getAll : a -> Node a -> List (Node a)
Get all nodes containing the provided value.
node 1 [ leaf 1 ]
|> getAll 1
--> [ node 1 [ leaf 1 ], leaf 1 ]
leaves : Node a -> List a
Retrieve all leaves (singletons) from a tree.
node "root"
[ leaf "a leaf"
, node "branch"
[ leaf "another leaf" ]
]
|> leaves
--> [ "a leaf", "another leaf" ]
level : Basics.Int -> Node a -> List (Node a)
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" ]
--> ]
maximum : Node comparable -> comparable
Compute the maximum value appearing in a tree.
node 1 [ leaf 100, node 2 [ leaf 3 ] ]
|> maximum
--> 100
minimum : Node comparable -> comparable
Compute the minimum value appearing in a tree.
node 100 [ leaf 99, node 1 [ leaf 98 ] ]
|> minimum
--> 1
parent : a -> Node a -> Maybe (Node a)
Retrieve 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" ])
path : a -> Node a -> List (Node a)
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" ]
seek : (a -> Basics.Bool) -> Node a -> List (Node a)
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 ]
siblings : a -> Node a -> List (Node a)
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" ] ]
all : (a -> Basics.Bool) -> Node a -> Basics.Bool
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)
--> False
any : (a -> Basics.Bool) -> Node a -> Basics.Bool
Check 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)
--> False
member : a -> Node a -> Basics.Bool
Check if a tree contains a value.
node "foo" [ node "bar" [ leaf "baz" ] ]
|> member "baz"
--> True
leaf "no"
|> member "yes"
--> False
mapChildren : (Node a -> Node a) -> Node a -> Node a
Map a Node's children.
node "root" [ leaf "foo", leaf "bar" ]
|> mapChildren (map String.toUpper)
--> node "root" [ leaf "FOO", leaf "BAR" ]
replaceChildren : List (Node a) -> Node a -> Node a
Replace the children of a Node.
replaceValue : a -> Node a -> Node a
Replace the value of a Node.
updateValue : (a -> a) -> Node a -> Node a
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!" }
mapChildrenAt : a -> (Node a -> Node a) -> Node a -> Node a
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 ] ]
replaceAt : a -> Node a -> Node a -> Node a
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" ]
replaceChildrenAt : a -> List (Node a) -> Node a -> Node a
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 ] ]
replaceValueAt : a -> a -> Node a -> Node a
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" ]
updateAt : a -> (Node a -> Node a) -> Node a -> Node a
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 ] ]
updateValueAt : a -> (a -> a) -> Node a -> Node a
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 -> Basics.Bool) -> Node a -> Maybe (Node a)
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 ])
flatMap : (Node a -> b) -> Node a -> List b
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 : Node a -> List (Node a)
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"
--> ]
foldl : (a -> b -> b) -> b -> Node a -> b
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"
foldr : (a -> b -> b) -> b -> Node a -> b
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 : (a -> b) -> Node a -> Node b
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" ] ]
refine : (a -> Basics.Bool) -> Node a -> Node a
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
--> ]
--> ]
--> ]
sortBy : (a -> comparable) -> Node a -> Node a
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 ]
sortWith : (a -> a -> Basics.Order) -> Node a -> Node a
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 ]
tuple : Node a -> Node a -> ( a, Maybe a )
Turn a Node into a tuple containing the value and the parent value, if any.
fromList : List ( a, Maybe a ) -> Maybe (Node a)
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" ] ])
toList : Node a -> List ( a, Maybe a )
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")
--> ]
decode : Json.Decode.Decoder a -> Json.Decode.Decoder (Node a)
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" ])
encode : (a -> Json.Encode.Value) -> Node a -> Json.Encode.Value
Encode a Node to JSON. You must provide an encoder for values.
import Json.Encode as Encode
node "foo" [ leaf "bar" ]
|> encode Encode.string
|> Encode.encode 0
--> "{\"value\":\"foo\",\"children\":[{\"value\":\"bar\",\"children\":[]}]}"