miyamoen / tree-with-zipper / Tree

This module implements Rose Tree data structure.

In computing, a multi-way tree or rose tree is a tree data structure with a variable and unbounded number of branches per node.

Types & Constructor


type Tree a
    = Tree a (Forest a)


type alias Forest a =
List (Tree a)

singleton : a -> Tree a

Puts value in minimal Tree context

singleton "foo"
    |> item
--> "foo"

Query

isEmpty : Tree a -> Basics.Bool

Check if Tree doesn't have any child.

singleton "foo"
    |> isEmpty
--> True

singleton "foo"
    |> insert (singleton "bar")
    |> isEmpty
--> False

item : Tree a -> a

Obtain item from Tree.

singleton "foo"
    |> item
    |> "foo"

children : Tree a -> List a

Obtain children items of Tree.

singleton "foo"
    |> insert (singleton "bar")
    |> insert (singleton "baz")
    |> children
--> [ "bar", "baz" ]

descendants : Tree a -> Forest a

Obtain descendants as Forest from the Tree.

singleton "foo"
    |> insert (singleton "bar")
    |> insert (singleton "baz")
    |> descendants
    |> List.map item
--> [ "bar", "baz" ]

singleton "foo"
    |> insert (singleton "bar" |> insert (singleton "baz"))
    |> descendants
    |> List.map (children)
--> [ [ "baz" ] ]

Modify

insert : Tree a -> Tree a -> Tree a

Insert one Tree as children another.

singleton 1
    |> insert (singleton 2)
    |> insert (singleton 3)
    |> children
--> [ 2, 3 ]

singleton 1
    |> insert (singleton 2)
    |> item
--> 1

Transforms

map : (a -> b) -> Tree a -> Tree b

Map function over Tree.

singleton 1
    |> map ((+) 1)
    |> item
--> 2

singleton 1
    |> insert (singleton 2)
    |> insert (singleton 3)
    |> map ((*) 2)
    |> children
--> [ 4, 6 ]

map2 : (a -> b -> c) -> Tree a -> Tree b -> Tree c

Map function over two Trees

map2 (+) (singleton 1) (singleton 5)
    |> item
--> 6

import Lazy.LList as LL

Tree 1 (List.fromList [ singleton 2, singleton 3, singleton 4 ])
    |> map2 (+) (Tree 5 <| List.fromList [ singleton 6, singleton 7 ])
    |> children
--> [ 8, 10 ]

filter : (a -> Basics.Bool) -> Tree a -> Tree a

Filter Tree children by given function.

This function goes from children of root downwards. This means that nodes that doesn't satisfy predicate are excluded and filter is never performed over their children even if on those it might pass.

Tree 1 [ singleton 2, singleton 3, singleton 4 ]
    |> filter ((>) 4)
    |> children
--> [ 2, 3 ]

Tree 1 [ insert (singleton 5) <| singleton 2, insert (singleton 6) <| singleton 3, singleton 4 ]
    |> filter ((<) 2)
    |> descendants
    |> List.map children
--> [ [ 6 ], [] ]

filterMap : (a -> Maybe b) -> Tree a -> Maybe (Tree b)

FilterMap on Tree. Works similarly to List.filterMap with same properties as filter. In case of filterMap even root node has to satisfy predicate otherwise Nothing is returned.

Tree 1 [ singleton 2, singleton 3, singleton 4 ]
    |> filterMap (\a -> if a < 4 then Just (a * 2) else Nothing)
    |> Maybe.map children
--> Just [ 4, 6 ]

Tree 1 [ singleton 2, singleton 3, singleton 4 ]
    |> filterMap (\a -> if a > 2 then Just (a * 2) else Nothing)
    |> Maybe.map children
--> Nothing

sort : Tree comparable -> Tree comparable

Sort tree.

singleton 10
    |> insert (singleton 5)
    |> insert (singleton 2)
    |> sort
    |> children
--> [ 2, 5 ]

it applies all levels:

import Lazy.LList as LL

singleton 10
    |> insert (Tree 20 <| (List.reverse << List.map singleton << List.range 1) 5)
    |> sort
    |> descendants
    |> List.map children
--> [ [ 1, 2, 3, 4, 5 ] ]

sortBy : (a -> comparable) -> Tree a -> Tree a

Sort Tree by a function.

singleton { val = 10 }
   |> insert (singleton { val = 7 })
   |> insert (singleton { val = 3 })
   |> sortBy .val
   |> children
--> [ { val = 3 }, { val = 7 } ]

it applies to all levels:

singleton { a = 10 }
    |> insert (Tree { a = 20 } <| (List.reverse << List.map (\v -> singleton { a = v }) << List.range 1) 3)
    |> sortBy .a
    |> descendants
    |> List.map children
--> [ [ { a = 1 }, { a = 2 }, { a = 3 } ] ]

sortWith : (a -> a -> Basics.Order) -> Tree a -> Tree a

Sort Tree using custom Ordering function

flippedComparison : comparable -> comparable -> Order
flippedComparison a b =
    case Basics.compare a b of
        LT -> GT
        EQ -> EQ
        GT -> LT

singleton 10
    |> insert (singleton 2)
    |> insert (singleton 5)
    |> sortWith flippedComparison
    |> children
--> [ 5, 2 ]

andMap : Tree a -> Tree (a -> b) -> Tree b

Chain map operations.

import Lazy.LList as LL

Tree Tuple.pair [ singleton Tuple.pair, singleton Tuple.pair, singleton Tuple.pair ]
    |> andMap (Tree 1 <| List.fromList [ singleton 2, singleton 3, singleton 4 ])
    |> andMap (Tree 5 <| List.fromList [ singleton 6, singleton 7 ])
    |> children
--> [ (2, 6), (3, 7) ]

flatten : Tree (Tree a) -> Tree a

Flatten Tree of Trees.

singleton (singleton 1)
    |> flatten
    |> item
--> 1

Tree (Tree "foo" [ singleton "bar"]) [ singleton <| singleton "baz" ]
    |> flatten
    |> children
--> [ "bar", "baz" ]

andThen : (a -> Tree b) -> Tree a -> Tree b

Map given function onto a Tree and flatten the result.

singleton "foo"
    |> insert (singleton "bar")
    |> insert (singleton "baz")
    |> andThen (\a -> Tree a [ singleton <| a ++ " fighter" ])
    |> children
--> [ "foo fighter", "bar", "baz" ]

Forest

forestMap : (a -> b) -> Forest a -> Forest b

Map function over Forest.

import Lazy.LList as LL

[ singleton 1, singleton 2, singleton 3 ]
    |> forestMap ((+) 1)
    |> List.map item
--> [ 2, 3, 4 ]

forestMap2 : (a -> b -> c) -> Forest a -> Forest b -> Forest c

Map function over two Forests.

[ singleton 1, singleton 2, singleton 3 ]
    |> forestMap2 (+) [ singleton 1, singleton 2]
    |> List.map item
    |> List.toList
--> [ 2, 4 ]