Reputation: 2079
I am going through some old courses online and came across this task:
data Tree a = Leaf
| Branch a (Tree a) (Tree a)
deriving (Show, Eq)
fold :: (a -> b -> b -> b) -> b -> Tree a -> b
fold _ acc Leaf = acc
fold f acc (Branch v l r) = f v (fold f acc l) (fold f acc r)
foldRT :: (a -> b -> b) -> b -> Tree a -> b
foldRT _ acc Leaf = acc
foldRT f acc (Branch v l r) = foldRT f (f v (foldRT f acc r)) l
The task is to rewrite foldRT
in terms of fold
. I have been stuck on it for ages and can't wrap my head around it.
A walk through would be greatly appreciated.
Upvotes: 2
Views: 253
Reputation: 34398
As its name and type signature suggest, foldRT
is a bona fide right fold for your tree (you can convince yourself of that by hand-evaluating it for something like Branch 1 (Branch 0 Leaf Leaf) (Branch 2 Leaf Leaf)
). That means implementing Foldable
will give you foldRT
: foldRT = foldr
. Why is that relevant? Because, in this case, it is much easier to implement foldMap
than it is to figure out how to write foldr
directly:
-- Note that l and r here aren't the subtrees, but the results of folding them.
instance Foldable Tree where
foldMap f = fold (\v l r -> l <> f v <> r) mempty
If you want to write foldRT
without relying on a Foldable
instance, all you need is expanding the foldMap
-based definition of foldr
(see the answers to this question for the details I'll gloss over here):
foldRT f z t = appEndo (foldMap (Endo . f) t) z
-- To make things less clumsy, let's use:
foldEndo f = appEndo . foldMap (Endo . f)
-- foldEndo f = flip (foldRT f)
foldEndo f = appEndo . fold (\v l r -> l <> Endo (f v) <> r) mempty
-- As we aren't mentioning foldMap anymore, we can drop the Endo wrappers.
-- mempty @(Endo _) = Endo id
-- Endo g <> Endo f = Endo (g . f)
foldEndo f = fold (\v l r -> l . f v . r) id
-- Bringing it all back home:
foldRT :: (a -> b -> b) -> b -> Tree a -> b
foldRT f z t = fold (\v l r -> l . f v . r) id t z
(Note that we ultimately reached a solution of the sort suggested by Carl, only through an indirect route.)
Upvotes: 1