Tree234

module Tree234(treeMap, treeCombine, treeRebuild, treeFromList, treeMapList,
               treeList, treeUpdate, treeSearch, treeAdd, initTree234, Tree234) where

data Tree234 a = Leaf |
                 Leaf2 a |
                 Leaf3 a a |
                 Leaf4 a a a |
                 Node2 a (Tree234 a) (Tree234 a) |
                 Node3 a a (Tree234 a) (Tree234 a) (Tree234 a) |
                 Node4 a a a (Tree234 a) (Tree234 a) (Tree234 a) (Tree234 a) 
                 deriving (Eq, Ord,Show)

initTree234 = Leaf

treeAdd comb cmp a t = treeAdd' comb cmp a id Node2 t

treeSearch fail cont p Leaf = fail
treeSearch fail cont p (Leaf2 a1) = p a1 fail (cont a1) fail
treeSearch fail cont p (Leaf3 a1 a2) =
    p a1 fail (cont a1) (p a2 fail (cont a2) fail)
treeSearch fail cont p (Leaf4 a1 a2 a3) =
    p a2 (p a1 fail (cont a1) fail) (cont a2) (p a3 fail (cont a3) fail)
treeSearch fail cont p (Node2 a1 t1 t2) =
    p a1 (treeSearch fail cont p t1) (cont a1) (treeSearch fail cont p t2)
treeSearch fail cont p (Node3 a1 a2 t1 t2 t3) =
    p a1
      (treeSearch fail cont p t1)
      (cont a1)
      (p a2
         (treeSearch fail cont p t2)
         (cont a2)
         (treeSearch fail cont p t3))
treeSearch fail cont p (Node4 a1 a2 a3 t1 t2 t3 t4) =
    p a2
      (p a1
         (treeSearch fail cont p t1)
         (cont a1)
         (treeSearch fail cont p t2))
      (cont a2)
      (p a3
         (treeSearch fail cont p t3)
         (cont a3)
         (treeSearch fail cont p t4))

treeUpdateFailed = error "treeUpdate couldn't find the node"

treeUpdate update p Leaf = Leaf
treeUpdate update p (Leaf2 a1) =
    p a1 treeUpdateFailed (Leaf2 (update a1)) treeUpdateFailed
treeUpdate update p (Leaf3 a1 a2) =
    p a1
      treeUpdateFailed
      (Leaf3 (update a1) a2)
      (p a2 treeUpdateFailed (Leaf3 a1 (update a2)) treeUpdateFailed)
treeUpdate update p (Leaf4 a1 a2 a3) =
    p a2
      (p a1 treeUpdateFailed (Leaf4 (update a1) a2 a3) treeUpdateFailed)
      (Leaf4 a1 (update a2) a3)
      (p a3 treeUpdateFailed (Leaf4 a1 a2 (update a3)) treeUpdateFailed)
treeUpdate update p (Node2 a1 t1 t2) =
    p a1
      (Node2 a1 (treeUpdate update p t1) t2)
      (Node2 (update a1) t1 t2)
      (Node2 a1 t1 (treeUpdate update p t2))
treeUpdate update p (Node3 a1 a2 t1 t2 t3) =
    p a1
      (Node3 a1 a2 (treeUpdate update p t1) t2 t3)
      (Node3 (update a1) a2 t1 t2 t3)
      (p a2
         (Node3 a1 a2 t1 (treeUpdate update p t2) t3)
         (Node3 a1 (update a2) t1 t2 t3)
         (Node3 a1 a2 t1 t2 (treeUpdate update p t3)))
treeUpdate update p (Node4 a1 a2 a3 t1 t2 t3 t4) =
    p a2
      (p a1
         (Node4 a1 a2 a3 (treeUpdate update p t1) t2 t3 t4)
         (Node4 (update a1) a2 a3 t1 t2 t3 t4)
         (Node4 a1 a2 a3 t1 (treeUpdate update p t2) t3 t4))
      (Node4 a1 (update a2) a3 t1 t2 t3 t4)
      (p a3
         (Node4 a1 a2 a3 t1 t2 (treeUpdate update p t3) t4)
         (Node4 a1 a2 (update a3) t1 t2 t3 t4)
         (Node4 a1 a2 a3 t1 t2 t3 (treeUpdate update p t4)))

treeMapList f Leaf = []
treeMapList f (Leaf2 a1) = f a1
treeMapList f (Leaf3 a1 a2) = f a1 ++ f a2
treeMapList f (Leaf4 a1 a2 a3) = f a1 ++ f a2 ++ f a3
treeMapList f (Node2 a1 t1 t2) =
    treeMapList f t1 ++ f a1 ++ treeMapList f t2
treeMapList f (Node3 a1 a2 t1 t2 t3) =
    treeMapList f t1 ++
    f a1 ++ treeMapList f t2 ++ f a2 ++ treeMapList f t3
treeMapList f (Node4 a1 a2 a3 t1 t2 t3 t4) =
    treeMapList f t1 ++
    f a1 ++
    treeMapList f t2 ++
    f a2 ++ treeMapList f t3 ++ f a3 ++ treeMapList f t4

treeMap f Leaf = Leaf
treeMap f (Leaf2 a1) = Leaf2 (f a1)
treeMap f (Leaf3 a1 a2) = Leaf3 (f a1) (f a2)
treeMap f (Leaf4 a1 a2 a3) = Leaf4 (f a1) (f a2) (f a3)
treeMap f (Node2 a1 t1 t2) =
    Node2 (f a1) (treeMap f t1) (treeMap f t2)
treeMap f (Node3 a1 a2 t1 t2 t3) =
    Node3 (f a1) (f a2) (treeMap f t1) (treeMap f t2) (treeMap f t3)
treeMap f (Node4 a1 a2 a3 t1 t2 t3 t4) =
    Node4 (f a1)
          (f a2)
          (f a3)
          (treeMap f t1)
          (treeMap f t2)
          (treeMap f t3)
          (treeMap f t4)

treeFromList comb cmp l = treeAddList comb cmp l Leaf

treeAddList comb cmp [] t = t
treeAddList comb cmp (x : xs) t =
    treeAddList comb cmp xs (treeAdd comb cmp x t)

treeRebuild comb cmp t = treeFromList comb cmp (treeMapList (: []) t)

treeCombine comb cmp t1 t2 =
    treeAddList comb cmp (treeMapList (: []) t2) t1

treeAdd' comb cmp a keep split Leaf = keep (Leaf2 a)
treeAdd' comb cmp a keep split (Leaf2 a1) =
    keep (cmp a a1 (Leaf3 a a1) (Leaf2 (comb a a1)) (Leaf3 a1 a))
treeAdd' comb cmp a keep split (Leaf3 a1 a2) =
    keep (cmp a
              a1
              (Leaf4 a a1 a2)
              (Leaf3 (comb a a1) a2)
              (cmp a a2 (Leaf4 a1 a a2) (Leaf3 a1 (comb a a2)) (Leaf4 a1 a2 a)))
treeAdd' comb cmp a keep split (Leaf4 a1 a2 a3) =
    cmp a
        a2
        (cmp a
             a1
             (split a2 (Leaf3 a a1) (Leaf2 a3))
             (keep (Leaf4 (comb a a1) a2 a3))
             (split a2 (Leaf3 a1 a) (Leaf2 a3)))
        (keep (Leaf4 a1 (comb a a2) a3))
        (cmp a
             a3
             (split a2 (Leaf2 a1) (Leaf3 a a3))
             (keep (Leaf4 a1 a2 (comb a a3)))
             (split a2 (Leaf2 a1) (Leaf3 a3 a)))
treeAdd' comb cmp a keep split (Node2 a1 t1 t2) =
    keep (cmp a
              a1
              (treeAdd' comb
                        cmp
                        a
                        (\t1' -> Node2 a1 t1' t2)
                        (\a0' -> \t0' -> \t1' -> Node3 a0' a1 t0' t1' t2)
                        t1)
              (Node2 (comb a a1) t1 t2)
              (treeAdd' comb
                        cmp
                        a
                        (\t2' -> Node2 a1 t1 t2')
                        (\a2' -> \t2' -> \t3' -> Node3 a1 a2' t1 t2' t3')
                        t2))
treeAdd' comb cmp a keep split (Node3 a1 a2 t1 t2 t3) =
    keep (cmp a
              a1
              (treeAdd' comb
                        cmp
                        a
                        (\t1' -> Node3 a1 a2 t1' t2 t3)
                        (\a0' -> \t0' -> \t1' -> Node4 a0' a1 a2 t0' t1' t2 t3)
                        t1)
              (Node3 (comb a a1) a2 t1 t2 t3)
              (cmp a
                   a2
                   (treeAdd' comb
                             cmp
                             a
                             (\t2' -> Node3 a1 a2 t1 t2' t3)
                             (\a1_5' ->
                              \t1_5' ->
                              \t2' -> Node4 a1 a1_5' a2 t1 t1_5' t2' t3)
                             t2)
                   (Node3 a1 (comb a a2) t1 t2 t3)
                   (treeAdd' comb
                             cmp
                             a
                             (\t3' -> Node3 a1 a2 t1 t2 t3')
                             (\a3' ->
                              \t3' -> \t4' -> Node4 a1 a2 a3' t1 t2 t3' t4')
                             t3)))
treeAdd' comb cmp a keep split (Node4 a1 a2 a3 t1 t2 t3 t4) =
    cmp a
        a2
        (cmp a
             a1
             (split a2
                    (treeAdd' comb
                              cmp
                              a
                              (\t1' -> Node2 a1 t1' t2)
                              (\a0' -> \t0' -> \t1' -> Node3 a0' a1 t0' t1' t2)
                              t1)
                    (Node2 a3 t3 t4))
             (keep (Node4 (comb a a1) a2 a3 t1 t2 t3 t4))
             (split a2
                    (treeAdd' comb
                              cmp
                              a
                              (\t2' -> Node2 a1 t1 t2')
                              (\a2' -> \t2' -> \t3' -> Node3 a1 a2' t1 t2' t3')
                              t2)
                    (Node2 a3 t3 t4)))
        (keep (Node4 a1 (comb a a2) a3 t1 t2 t3 t4))
        (cmp a
             a3
             (split a2
                    (Node2 a1 t1 t2)
                    (treeAdd' comb
                              cmp
                              a
                              (\t3' -> Node2 a3 t3' t4)
                              (\a2' -> \t2' -> \t3' -> Node3 a2' a3 t2' t3' t4)
                              t3))
             (keep (Node4 a1 a2 (comb a a3) t1 t2 t3 t4))
             (split a2
                    (Node2 a1 t1 t2)
                    (treeAdd' comb
                              cmp
                              a
                              (\t4' -> Node2 a3 t3 t4')
                              (\a4' -> \t4' -> \t5' -> Node3 a3 a4' t3 t4' t5')
                              t4)))

treeList t = treeMapList (: []) t