Search code examples
haskelltreeappendfold

How to write a function of type a-> b -> b -> b for folding a tree


Some background: I have a foldT function (like foldr but for trees) of the following type in Haskell.

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

This foldT only takes type (a -> b -> b -> b) as an input function.

I am trying to find a way to convert my tree into a list, and cannot figure out a way to make my append function take the form (a -> b -> b -> b).

The following is ineffective because it is not the correct type:

append x y z = append x:y:z 

Any help would be appreciated.

Thank you!


Solution

  • As you haven't posted it, I will assume your tree is...

    data Tree a = Leaf | Node a (Tree a) (Tree a)
    

    ... and that the a -> b -> b -> b argument to foldT takes the fields of the Node constructor in the same order they were declared.

    I am trying to find a way to convert my tree into a list

    Let's begin tackling this by following the types:

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

    You want to flatten it into a list, so the result type of your function must be [a]:

    treeToList :: Tree a -> [a]
    

    That give us a good idea on how to continue:

    treeToList t = foldT f z t
    

    With:

    f :: a -> [a] -> [a] -> [a]
    z :: [a]
    t :: Tree a
    

    Now, onward to the arguments. z is what will be inserted in lieu of the valueless Leafs, and so it must be []. As for f, it must combine the sublists created from the left and right branches with the value directly in the Node. Assuming an in-order traversal, we have:

     treeToList t = foldT (\x l r -> l ++ x : r) [] t
    

    Or, without mentioning t:

     treeToList = foldT (\x l r -> l ++ x : r) []
    

    And that's it. One caveat is that repeatedly using left-nested (++) (which will happen in this case, as foldT walks down the branches recursively) can get quite inefficient. In a situation in which you would care about performance it would be worth considering alternative ways of implementing the concatenating function, such as difference lists.

    P.S.: A note about terminology. Saying that a function is "like foldr but for trees" is ambiguous, as there are two well-known kinds of functions analogous to foldr. First, you have the methods of the Foldable class (cf. Benjamin Hodgson's answer), which flatten the tree into a list as they fold it, no matter what you do. Then there are the more powerful catamorphisms, such as the foldT you are using, which are able to make use of the tree structure.