Search code examples
haskellfunctional-programminginorder

Flattening a tree in haskell using in-order traversal


I want to implement flattenning a tree using my foldTree function that I defined and in-order traversal.Which should return a list after flattening.

data Tree t = Leaf t
        | Tree (Tree t) t (Tree t)


foldTree :: (t1 -> t -> t1 -> t1) -> (t -> t1) -> Tree t -> t1
foldTree treeFn leafFn tree =
case tree of
  Leaf v -> leafFn v
  Tree leftTree q rightTree -> treeFn (foldTree treeFn leafFn leftTree) q (foldTree treeFn leafFn rightTree)


Input : foldTree (\t1 t t2->t1 + 5*t + t2) (\x->x+9) (Leaf 5)
Expected Output : 14

Input : foldTree (\t1 t t2->t1 + 3*t + t2) (\x->x+5) (Tree (Leaf 3) 2 (Leaf 4))
Expected Output : 23

I tried the following code but it uses recursion.I want to call foldTree from flattenTree to implement the flattening of tree instead of making a recursive call to flatTree.(Using foldTree functions in flattenTree).Can anyone help me on how to integrate it.

flatTree :: Tree a -> [a]
flatTree tree = 
case tree of
    Leaf v -> [v]
    Tree p v r -> (flatTree p) ++ [v] ++ (flatTree r) 

Input: flatTree (Tree (Leaf 5) 3 (Tree (Leaf 3) 2 (Leaf 4)))
Expected output : [5,3,3,2,4]

Solution

  • Look at the type of foldTree.

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

    You can see that b is the result type of the catamorphism. foldTree works by folding each sub-tree to obtain a result b for each, then combining them using the folding function.

    Since you want the result to be a flattened list of the tree's elements, let's set b ~ [a].

    foldTree :: ([a] -> a -> [a] -> [a]) -> (a -> [a]) -> Tree a -> [a]
    

    So the second argument of foldTree should be something which injects a single element a into a list [a], and the first should be one that combines two lists with an element to make a bigger list.

    flatTree = foldTree (\xs x ys -> xs ++ x : ys) (\x -> [x])
    

    Incidentally, GHC is able to write your flatTree function for you, just by looking at the structure of the type. flatTree :: Tree a -> [a] matches the type of toList :: Foldable f => f a -> [a], which is part of the Foldable class. All you need to do is say the magic words, deriving Foldable, and GHC will spit out an instance of Foldable.

    {-# LANGUAGE DeriveFoldable #-}
    
    data Tree t = Leaf t
                | Tree (Tree t) t (Tree t)
                deriving Foldable
    
    flatTree :: Tree a -> [a]
    flatTree = toList
    

    Because of the way the Tree constructor is laid out, toList will perform an in-order traversal. This can be varied by adjusting the definition of the Tree constructor.