Skip to content

Trees

I've already shown you the implementation of foldMap for trees so we could play with them before. Here it is again:

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

instance Foldable Tree where
    foldMap f = go mempty
      where
        go prod Empty        = prod
        go prod (Node l x r) = go (f x <> go prod r) l

We are required to implement a right-to-left fold, so we mimic foldr. Our initial accumulator, which I call prod for product here, is mempty. Next we need to inspect the tree elements right to left and, for each tree element x, multiply f x with the product of the elements to the right of x. For the empty tree, the final result is clearly the initial accumulator value prod, so we simply return it. For a non-empty tree consisting of a root element x, a left subtree l, and a right subtree r, we need to start by accumulating the elements in the right subtree. We do this using go prod r. Next we need to add x to the result. We do this by calling f to convert x into a monoid value and then multiplying f x with go prod r using the monoid multiplication <>. Whatever value this produces is the result of accumulating all elements to the right of the left subtree (because x and r are both to the right of l). Thus, we finish the accumulation by calling go recursively on l, with f x <> go prod r as the initial product.

The implementation of foldl does the same, but it walks the tree left to right:

instance Foldable Tree where
    foldl f = go
      where
        go accum Empty      = accum
        go accum (Node l r) = go (f (go accum l) x) r

We accumulate the left subtree l by calling go accum l. We add x to the current accumulator value, by calling f with arguments go accum l and x. And finally we finish the accumulation by recursively calling go on r with f (go accum l) x as the initial accumulator value.