Functional Data Structures

Tessa Kelly

engineer at NoRedInk

@t_kelly9

Binary Tree API

module BinaryTree
    exposing
        ( BinaryTree
        , new
        , empty
        , member
        , insert
        , remove
        )

Array
Dict
Tree I & II

Array Based

Strategy:

  • Use Array as our base
  • Derive child indices
  • Hope for a complete binary tree
type alias BinaryTree comparable =
    Array (Maybe comparable)


leftChild : Int -> Int
leftChild index =
    2 * index + 1


rightChild : Int -> Int
rightChild index =
    2 * index + 2


empty : BinaryTree comparable
empty =
    Array.empty


new : comparable -> BinaryTree comparable
new value =
    Array.initialize 1 (\_ -> Just value)


member : comparable -> BinaryTree comparable -> Bool
member =
    memberAt 0


memberAt : Int -> comparable -> BinaryTree comparable -> Bool
memberAt index value tree =
    case Array.get index tree of
        Just (Just nodeValue) ->
            if value < nodeValue then
                memberAt (leftChild index) value tree
            else if value > nodeValue then
                memberAt (rightChild index) value tree
            else
                value == nodeValue

        _ ->
            False


insert : comparable -> BinaryTree comparable -> BinaryTree comparable
insert =
    insertAt 0


insertAt : Int -> comparable -> BinaryTree comparable -> BinaryTree comparable
insertAt index value tree =
    case Array.get index tree of
        Just (Just nodeValue) ->
            if value < nodeValue then
                insertAt (leftChild index) value tree
            else if value > nodeValue then
                insertAt (rightChild index) value tree
            else
                tree

        Just Nothing ->
            Array.set index (Just value) tree

        Nothing ->
            fillWithEmptiesUntil index value tree


fillWithEmptiesUntil : Int -> comparable -> BinaryTree comparable -> BinaryTree comparable
fillWithEmptiesUntil index value tree =
    Array.repeat (index - Array.length tree) Nothing
        |> Array.push (Just value)
        |> Array.append tree


remove : comparable -> BinaryTree comparable -> BinaryTree comparable
remove =
    removeAt 0


removeAt : Int -> comparable -> BinaryTree comparable -> BinaryTree comparable
removeAt index value tree =
    case Array.get index tree of
        Just (Just nodeValue) ->
            if value < nodeValue then
                removeAt (leftChild index) value tree
            else if value > nodeValue then
                removeAt (rightChild index) value tree
            else
                case ( Array.get (leftChild index) tree, Array.get (rightChild index) tree ) of
                    ( Just (Just leftValue), _ ) ->
                        Array.set index (Just leftValue) (removeAt (leftChild index) leftValue tree)

                    ( _, Just (Just rightValue) ) ->
                        Array.set index (Just rightValue) (removeAt (rightChild index) rightValue tree)

                    ( _, _ ) ->
                        Array.set index Nothing tree

        _ ->
            tree

Shape of a Node

type alias BinaryTree comparable =
    Array (Maybe comparable)

Creating a Binary Tree

type alias BinaryTree comparable =
    Array (Maybe comparable)


empty : BinaryTree comparable
empty =
    Array.empty


new : comparable -> BinaryTree comparable
new value =
    Array.initialize 1 (\_ -> Just value)

Checking for Values

member : comparable -> BinaryTree comparable -> Bool
member =
    memberAt 0


memberAt : Int -> comparable -> BinaryTree comparable -> Bool
memberAt index value tree =
    case Array.get index tree of
        Just (Just nodeValue) ->
            if value < nodeValue then
                memberAt (leftChild index) value tree
            else if value > nodeValue then
                memberAt (rightChild index) value tree
            else
                value == nodeValue

        _ ->
            False

Inserting Values

insert : comparable -> BinaryTree comparable -> BinaryTree comparable
insert =
    insertAt 0


insertAt : Int -> comparable -> BinaryTree comparable -> BinaryTree comparable
insertAt index value tree =
    case Array.get index tree of
        Just (Just nodeValue) ->
            if value < nodeValue then
                insertAt (leftChild index) value tree
            else if value > nodeValue then
                insertAt (rightChild index) value tree
            else
                tree

        Just Nothing ->
            Array.set index (Just value) tree

        Nothing ->
            .... uh oh!!!
insert : comparable -> BinaryTree comparable -> BinaryTree comparable
insert =
    insertAt 0


insertAt : Int -> comparable -> BinaryTree comparable -> BinaryTree comparable
insertAt index value tree =
    case Array.get index tree of
        Just (Just nodeValue) ->
            if value < nodeValue then
                insertAt (leftChild index) value tree
            else if value > nodeValue then
                insertAt (rightChild index) value tree
            else
                tree

        Just Nothing ->
            Array.set index (Just value) tree

        Nothing ->
            fillWithEmptiesUntil index value tree


fillWithEmptiesUntil : Int -> comparable -> BinaryTree comparable -> BinaryTree comparable
fillWithEmptiesUntil index value tree =
    Array.repeat (index - Array.length tree) Nothing
        |> Array.push (Just value)
        |> Array.append tree
remove : comparable -> BinaryTree comparable -> BinaryTree comparable
remove =
    removeAt 0


removeAt : Int -> comparable -> BinaryTree comparable -> BinaryTree comparable
removeAt index value tree =
    case Array.get index tree of
        Just (Just nodeValue) ->
            if value < nodeValue then
                removeAt (leftChild index) value tree
            else if value > nodeValue then
                removeAt (rightChild index) value tree
            else
                case ( Array.get (leftChild index) tree, Array.get (rightChild index) tree ) of
                    ( Just (Just leftValue), _ ) ->
                        Array.set index (Just leftValue) (removeAt (leftChild index) leftValue tree)

                    ( _, Just (Just rightValue) ) ->
                        Array.set index (Just rightValue) (removeAt (rightChild index) rightValue tree)

                    ( _, _ ) ->
                        Array.set index Nothing tree

        _ ->
            tree

Removing Values

Eek!
Types, halp!
 

Adding a Node type

This helps make our code more readable by cutting out the bananas `Just Nothing` business, but it doesn't solve all of our problems with this implementation.

type alias BinaryTree comparable =
    Array (Node comparable)


type Node comparable
    = Node comparable
    | Empty


insertAt : Int -> comparable -> BinaryTree comparable -> BinaryTree comparable
insertAt index value tree =
    case Array.get index tree of
        Just (Node nodeValue) ->
            if value < nodeValue then
                insertAt (leftChild index) value tree
            else if value > nodeValue then
                insertAt (rightChild index) value tree
            else
                tree

        Just Empty ->
            Array.set index (Node value) tree

        Nothing ->
            fillWithEmptiesUntil index value tree


removeAt : Int -> comparable -> BinaryTree comparable -> BinaryTree comparable
removeAt index value tree =
    case Array.get index tree of
        Just (Node nodeValue) ->
            if value < nodeValue then
                removeAt (leftChild index) value tree
            else if value > nodeValue then
                removeAt (rightChild index) value tree
            else
                case ( Array.get (leftChild index) tree, Array.get (rightChild index) tree ) of
                    ( Just (Node leftValue), _ ) ->
                        Array.set index (Node leftValue) (removeAt (leftChild index) leftValue tree)

                    ( _, Just (Node rightValue) ) ->
                        Array.set index (Node rightValue) (removeAt (rightChild index) rightValue tree)

                    ( _, _ ) ->
                        Array.set index Empty tree

        _ ->
            tree

Dict Based

Strategy:

  • Use Dict as our base
  • Derive child indices
  • Continue using helpers to our advantage
     
type alias BinaryTree comparable =
    Dict Int comparable


empty : BinaryTree comparable
empty =
    Dict.empty


member : comparable -> BinaryTree comparable -> Bool
member =
    memberAt 0


memberAt : Int -> comparable -> BinaryTree comparable -> Bool
memberAt index value tree =
    case Dict.get index tree of
        Just nodeValue ->
            if value < nodeValue then
                memberAt (leftChild index) value tree
            else if value > nodeValue then
                memberAt (rightChild index) value tree
            else
                value == nodeValue

        _ ->
            False


insert : comparable -> BinaryTree comparable -> BinaryTree comparable
insert =
    insertAt 0


insertAt : Int -> comparable -> BinaryTree comparable -> BinaryTree comparable
insertAt index value tree =
    case Dict.get index tree of
        Just nodeValue ->
            if value < nodeValue then
                insertAt (leftChild index) value tree
            else if value > nodeValue then
                insertAt (rightChild index) value tree
            else
                tree

        Nothing ->
            Dict.insert index value tree


remove : comparable -> BinaryTree comparable -> BinaryTree comparable
remove =
    removeAt 0


removeAt : Int -> comparable -> BinaryTree comparable -> BinaryTree comparable
removeAt index value tree =
    case Dict.get index tree of
        Just nodeValue ->
            if value < nodeValue then
                removeAt (leftChild index) value tree
            else if value > nodeValue then
                removeAt (rightChild index) value tree
            else
                case ( Dict.get (leftChild index) tree, Dict.get (rightChild index) tree ) of
                    ( Just leftValue, _ ) ->
                        Dict.insert index leftValue (removeAt (leftChild index) leftValue tree)

                    ( _, Just rightValue ) ->
                        Dict.insert index rightValue (removeAt (rightChild index) rightValue tree)

                    ( Nothing, Nothing ) ->
                        Dict.remove index tree

        _ ->
            tree


leftChild : Int -> Int
leftChild index =
    2 * index + 1


rightChild : Int -> Int
rightChild index =
    2 * index + 2


new : comparable -> BinaryTree comparable
new value =
    Dict.singleton 0 value

Creating a Binary Tree

type alias BinaryTree comparable =
    Dict Int comparable


empty : BinaryTree comparable
empty =
    Dict.empty


new : comparable -> BinaryTree comparable
new value =
    Dict.singleton 0 value


member : comparable -> BinaryTree comparable -> Bool
member =
    memberAt 0

Checking for Values

member : comparable -> BinaryTree comparable -> Bool
member =
    memberAt 0


memberAt : Int -> comparable -> BinaryTree comparable -> Bool
memberAt index value tree =
    case Dict.get index tree of
        Just nodeValue ->
            if value < nodeValue then
                memberAt (leftChild index) value tree
            else if value > nodeValue then
                memberAt (rightChild index) value tree
            else
                value == nodeValue

        _ ->
            False

Inserting Values

insert : comparable -> BinaryTree comparable -> BinaryTree comparable
insert =
    insertAt 0


insertAt : Int -> comparable -> BinaryTree comparable -> BinaryTree comparable
insertAt index value tree =
    case Dict.get index tree of
        Just nodeValue ->
            if value < nodeValue then
                insertAt (leftChild index) value tree
            else if value > nodeValue then
                insertAt (rightChild index) value tree
            else
                tree

        Nothing ->
            Dict.insert index value tree

Removing Values

remove : comparable -> BinaryTree comparable -> BinaryTree comparable
remove =
    removeAt 0


removeAt : Int -> comparable -> BinaryTree comparable -> BinaryTree comparable
removeAt index value tree =
    case Dict.get index tree of
        Just nodeValue ->
            if value < nodeValue then
                removeAt (leftChild index) value tree
            else if value > nodeValue then
                removeAt (rightChild index) value tree
            else
                case ( Dict.get (leftChild index) tree, Dict.get (rightChild index) tree ) of
                    ( Just leftValue, _ ) ->
                        Dict.insert index leftValue (removeAt (leftChild index) leftValue tree)

                    ( _, Just rightValue ) ->
                        Dict.insert index rightValue (removeAt (rightChild index) rightValue tree)

                    ( Nothing, Nothing ) ->
                        Dict.remove index tree

        _ ->
            tree

Tree Based, I

Strategy:

  • Use "pointers"
  • Pretend records have entirely analogous uses to JavaScript Objects
  • Hope that the types stay nice
type BinaryTree comparable
    = Node
        { value : comparable
        , left : BinaryTree comparable
        , right : BinaryTree comparable
        }
    | Empty


empty : BinaryTree comparable
empty =
    Empty


new : comparable -> BinaryTree comparable
new value =
    Node
        { value = value
        , left = Empty
        , right = Empty
        }


member : comparable -> BinaryTree comparable -> Bool
member value tree =
    case tree of
        Node node ->
            if value < node.value then
                member value node.left
            else if value > node.value then
                member value node.right
            else
                value == node.value

        Empty ->
            False


insert : comparable -> BinaryTree comparable -> BinaryTree comparable
insert value tree =
    case tree of
        Node node ->
            if value < node.value then
                Node
                    { value = node.value
                    , left = insert value node.left
                    , right = node.right
                    }
            else if value > node.value then
                Node
                    { value = node.value
                    , left = node.left
                    , right = insert value node.right
                    }
            else
                Node node

        Empty ->
            new value


remove : comparable -> BinaryTree comparable -> BinaryTree comparable
remove value tree =
    case tree of
        Node node ->
            if value < node.value then
                Node
                    { value = node.value
                    , left = remove value node.left
                    , right = node.right
                    }
            else if value > node.value then
                Node
                    { value = node.value
                    , left = node.left
                    , right = remove value node.right
                    }
            else
                case ( node.left, node.right ) of
                    -- No children to consider
                    ( Empty, Empty ) ->
                        empty

                    -- One child, on the right
                    ( Empty, Node rightTree ) ->
                        Node rightTree

                    -- One child, on the left
                    ( Node leftTree, Empty ) ->
                        Node leftTree

                    -- Two children, right and left
                    ( Node leftTree, Node rightTree ) ->
                        Node
                            { value = rightTree.value
                            , left = Node leftTree
                            , right = remove rightTree.value (Node rightTree)
                            }

        Empty ->
            Empty
type BinaryTree comparable
    = Node
        { value : comparable
        , left : BinaryTree comparable
        , right : BinaryTree comparable
        }
    | Empty

Shape of a Node

type BinaryTree comparable
    = Node
        { value : comparable
        , left : BinaryTree comparable
        , right : BinaryTree comparable
        }
    | Empty


empty : BinaryTree comparable
empty =
    Empty


new : comparable -> BinaryTree comparable
new value =
    Node
        { value = value
        , left = Empty
        , right = Empty
        }

Creating a Binary Tree

insert : comparable -> BinaryTree comparable -> BinaryTree comparable
insert value tree =
    case tree of
        Node node ->
            if value < node.value then
                Node
                    { value = node.value
                    , left = insert value node.left
                    , right = node.right
                    }
            else if value > node.value then
                Node
                    { value = node.value
                    , left = node.left
                    , right = insert value node.right
                    }
            else
                Node node

        Empty ->
            new value

Inserting Values

remove : comparable -> BinaryTree comparable -> BinaryTree comparable
remove value tree =
    case tree of
        Node node ->
            if value < node.value then
                Node
                    { value = node.value
                    , left = remove value node.left
                    , right = node.right
                    }
            else if value > node.value then
                Node
                    { value = node.value
                    , left = node.left
                    , right = remove value node.right
                    }
            else
                case ( node.left, node.right ) of
                    ( Empty, Empty ) ->
                        empty

                    ( Empty, Node rightTree ) ->
                        Node rightTree

                    ( Node leftTree, Empty ) ->
                        Node leftTree

                    ( Node leftTree, Node rightTree ) ->
                        Node
                            { value = rightTree.value
                            , left = Node leftTree
                            , right = remove rightTree.value (Node rightTree)
                            }

        Empty ->
            Empty

Tree Based, II

Strategy:

  • Create types to describe the shape of a node
  • Use casing to our advantage
type BinaryTree comparable
    = Node comparable (BinaryTree comparable) (BinaryTree comparable)
    | Empty


empty : BinaryTree comparable
empty =
    Empty


new : comparable -> BinaryTree comparable
new value =
    Node value empty empty


member : comparable -> BinaryTree comparable -> Bool
member value tree =
    case tree of
        Node nodeValue left right ->
            if value < nodeValue then
                member value left
            else if value > nodeValue then
                member value right
            else
                value == nodeValue

        Empty ->
            False


insert : comparable -> BinaryTree comparable -> BinaryTree comparable
insert value tree =
    case tree of
        Node nodeValue left right ->
            if value < nodeValue then
                Node nodeValue (insert value left) right
            else if value > nodeValue then
                Node nodeValue left (insert value right)
            else
                Node nodeValue left right

        Empty ->
            new value


remove : comparable -> BinaryTree comparable -> BinaryTree comparable
remove value tree =
    case tree of
        Node nodeValue left right ->
            if value < nodeValue then
                Node nodeValue (remove value left) right
            else if value > nodeValue then
                Node nodeValue left (remove value left)
            else
                case ( left, right ) of
                    ( Empty, Empty ) ->
                        empty

                    ( Empty, (Node _ _ _) as rightChild ) ->
                        rightChild

                    ( (Node _ _ _) as leftChild, Empty ) ->
                        leftChild

                    ( Node _ _ _, (Node rightChildValue _ _) as rightChild ) ->
                        Node rightChildValue left (remove value rightChild)

        Empty ->
            Empty

Shape of a Node


type BinaryTree comparable
    = Node comparable (BinaryTree comparable) (BinaryTree comparable)
    | Empty

Creating a Binary Tree

type BinaryTree comparable
    = Node comparable (BinaryTree comparable) (BinaryTree comparable)
    | Empty


empty : BinaryTree comparable
empty =
    Empty


new : comparable -> BinaryTree comparable
new value =
    Node value empty empty

Inserting Values

insert : comparable -> BinaryTree comparable -> BinaryTree comparable
insert value tree =
    case tree of
        Node nodeValue left right ->
            if value < nodeValue then
                Node nodeValue (insert value left) right
            else if value > nodeValue then
                Node nodeValue left (insert value right)
            else
                Node nodeValue left right

        Empty ->
            new value

Checking for Values

member : comparable -> BinaryTree comparable -> Bool
member value tree =
    case tree of
        Node nodeValue left right ->
            if value < nodeValue then
                member value left
            else if value > nodeValue then
                member value right
            else
                value == nodeValue

        Empty ->
            False
remove : comparable -> BinaryTree comparable -> BinaryTree comparable
remove value tree =
    case tree of
        Node nodeValue left right ->
            if value < nodeValue then
                Node nodeValue (remove value left) right
            else if value > nodeValue then
                Node nodeValue left (remove value left)
            else
                case ( left, right ) of
                    ( Empty, Empty ) ->
                        empty

                    ( Empty, (Node _ _ _) as rightChild ) ->
                        rightChild

                    ( (Node _ _ _) as leftChild, Empty ) ->
                        leftChild

                    ( Node _ _ _, (Node rightChildValue _ _) as rightChild ) ->
                        Node rightChildValue left (remove value rightChild)

        Empty ->
            Empty

Removing Values

Thanks!

Enjoy the rest of the conference!

@t_kelly9

type alias BinaryTree comparable =
    Array (Node comparable)


type Node comparable
    = Node comparable
    | Empty


empty : BinaryTree comparable
empty =
    Array.empty


new : comparable -> BinaryTree comparable
new value =
    Array.initialize 1 (\_ -> Node value)


member : comparable -> BinaryTree comparable -> Bool
member =
    memberAt 0


memberAt : Int -> comparable -> BinaryTree comparable -> Bool
memberAt index value tree =
    case Array.get index tree of
        Just (Node nodeValue) ->
            if value < nodeValue then
                memberAt (leftChild index) value tree
            else if value > nodeValue then
                memberAt (rightChild index) value tree
            else
                value == nodeValue

        _ ->
            False


insert : comparable -> BinaryTree comparable -> BinaryTree comparable
insert =
    insertAt 0


insertAt : Int -> comparable -> BinaryTree comparable -> BinaryTree comparable
insertAt index value tree =
    case Array.get index tree of
        Just (Node nodeValue) ->
            if value < nodeValue then
                insertAt (leftChild index) value tree
            else if value > nodeValue then
                insertAt (rightChild index) value tree
            else
                tree

        Just Empty ->
            Array.set index (Node value) tree

        Nothing ->
            fillWithEmptiesUntil index value tree


fillWithEmptiesUntil : Int -> comparable -> BinaryTree comparable -> BinaryTree comparable
fillWithEmptiesUntil index value tree =
    Array.repeat (index - Array.length tree) Empty
        |> Array.push (Node value)
        |> Array.append tree


remove : comparable -> BinaryTree comparable -> BinaryTree comparable
remove =
    removeAt 0


removeAt : Int -> comparable -> BinaryTree comparable -> BinaryTree comparable
removeAt index value tree =
    case Array.get index tree of
        Just (Node nodeValue) ->
            if value < nodeValue then
                removeAt (leftChild index) value tree
            else if value > nodeValue then
                removeAt (rightChild index) value tree
            else
                case ( Array.get (leftChild index) tree, Array.get (rightChild index) tree ) of
                    ( Just (Node leftValue), _ ) ->
                        Array.set index (Node leftValue) (removeAt (leftChild index) leftValue tree)

                    ( _, Just (Node rightValue) ) ->
                        Array.set index (Node rightValue) (removeAt (rightChild index) rightValue tree)

                    ( _, _ ) ->
                        Array.set index Empty tree

        _ ->
            tree


leftChild : Int -> Int
leftChild index =
    2 * index + 1


rightChild : Int -> Int
rightChild index =
    2 * index + 2
type alias BinaryTree comparable =
    Dict Int comparable


empty : BinaryTree comparable
empty =
    Dict.empty


new : comparable -> BinaryTree comparable
new value =
    Dict.singleton 0 value


member : comparable -> BinaryTree comparable -> Bool
member =
    memberAt 0


memberAt : Int -> comparable -> BinaryTree comparable -> Bool
memberAt index value tree =
    case Dict.get index tree of
        Just nodeValue ->
            if value < nodeValue then
                memberAt (leftChild index) value tree
            else if value > nodeValue then
                memberAt (rightChild index) value tree
            else
                value == nodeValue

        _ ->
            False


insert : comparable -> BinaryTree comparable -> BinaryTree comparable
insert =
    insertAt 0


insertAt : Int -> comparable -> BinaryTree comparable -> BinaryTree comparable
insertAt index value tree =
    case Dict.get index tree of
        Just nodeValue ->
            if value < nodeValue then
                insertAt (leftChild index) value tree
            else if value > nodeValue then
                insertAt (rightChild index) value tree
            else
                tree

        Nothing ->
            Dict.insert index value tree


remove : comparable -> BinaryTree comparable -> BinaryTree comparable
remove =
    removeAt 0


removeAt : Int -> comparable -> BinaryTree comparable -> BinaryTree comparable
removeAt index value tree =
    case Dict.get index tree of
        Just nodeValue ->
            if value < nodeValue then
                removeAt (leftChild index) value tree
            else if value > nodeValue then
                removeAt (rightChild index) value tree
            else
                case ( Dict.get (leftChild index) tree, Dict.get (rightChild index) tree ) of
                    ( Just leftValue, _ ) ->
                        Dict.insert index leftValue (removeAt (leftChild index) leftValue tree)

                    ( _, Just rightValue ) ->
                        Dict.insert index rightValue (removeAt (rightChild index) rightValue tree)

                    ( Nothing, Nothing ) ->
                        Dict.remove index tree

        _ ->
            tree


leftChild : Int -> Int
leftChild index =
    2 * index + 1


rightChild : Int -> Int
rightChild index =
    2 * index + 2
type BinaryTree comparable
    = Node
        { value : comparable
        , left : BinaryTree comparable
        , right : BinaryTree comparable
        }
    | Empty


empty : BinaryTree comparable
empty =
    Empty


new : comparable -> BinaryTree comparable
new value =
    Node
        { value = value
        , left = Empty
        , right = Empty
        }


member : comparable -> BinaryTree comparable -> Bool
member value tree =
    case tree of
        Node node ->
            if value < node.value then
                member value node.left
            else if value > node.value then
                member value node.right
            else
                value == node.value

        Empty ->
            False


insert : comparable -> BinaryTree comparable -> BinaryTree comparable
insert value tree =
    case tree of
        Node node ->
            if value < node.value then
                Node
                    { value = node.value
                    , left = insert value node.left
                    , right = node.right
                    }
            else if value > node.value then
                Node
                    { value = node.value
                    , left = node.left
                    , right = insert value node.right
                    }
            else
                Node node

        Empty ->
            new value


remove : comparable -> BinaryTree comparable -> BinaryTree comparable
remove value tree =
    case tree of
        Node node ->
            if value < node.value then
                Node
                    { value = node.value
                    , left = remove value node.left
                    , right = node.right
                    }
            else if value > node.value then
                Node
                    { value = node.value
                    , left = node.left
                    , right = remove value node.right
                    }
            else
                case ( node.left, node.right ) of
                    ( Empty, Empty ) ->
                        empty

                    ( Empty, Node rightTree ) ->
                        Node rightTree

                    ( Node leftTree, Empty ) ->
                        Node leftTree

                    ( Node leftTree, Node rightTree ) ->
                        Node
                            { value = rightTree.value
                            , left = Node leftTree
                            , right = remove rightTree.value (Node rightTree)
                            }

        Empty ->
            Empty
type BinaryTree comparable
    = Node comparable (BinaryTree comparable) (BinaryTree comparable)
    | Empty


empty : BinaryTree comparable
empty =
    Empty


new : comparable -> BinaryTree comparable
new value =
    Node value empty empty


member : comparable -> BinaryTree comparable -> Bool
member value tree =
    case tree of
        Node nodeValue left right ->
            if value < nodeValue then
                member value left
            else if value > nodeValue then
                member value right
            else
                value == nodeValue

        Empty ->
            False


insert : comparable -> BinaryTree comparable -> BinaryTree comparable
insert value tree =
    case tree of
        Node nodeValue left right ->
            if value < nodeValue then
                Node nodeValue (insert value left) right
            else if value > nodeValue then
                Node nodeValue left (insert value right)
            else
                Node nodeValue left right

        Empty ->
            new value


remove : comparable -> BinaryTree comparable -> BinaryTree comparable
remove value tree =
    case tree of
        Node nodeValue left right ->
            if value < nodeValue then
                Node nodeValue (remove value left) right
            else if value > nodeValue then
                Node nodeValue left (remove value left)
            else
                case ( left, right ) of
                    ( Empty, Empty ) ->
                        empty

                    ( Empty, (Node _ _ _) as rightChild ) ->
                        rightChild

                    ( (Node _ _ _) as leftChild, Empty ) ->
                        leftChild

                    ( Node _ _ _, (Node rightChildValue _ _) as rightChild ) ->
                        Node rightChildValue left (remove value rightChild)

        Empty ->
            Empty

Thanks!

Enjoy the rest of the conference!

@t_kelly9

Functional Data Structures

By Tessa K

Functional Data Structures

Elegant data structures are different across programming languages, and creating them should be approached differently. Leverage Elm’s union types to build simple and readable structures, beginning with binary trees. Writing a binary tree might be a familiar task in JavaScript or Ruby, and it might seem like a very similar problem in Elm. While it’s possible to create data structures in Elm that are very similar to ones written in languages that aren’t strictly functional and that don’t have types, there are better approaches. This talk will explore a few different implementations and recommendations, and assumes an audience without extensive academic ML-family language experience.

  • 938