For example, I have some data type. Let it be a binary tree:
data Tree a = Leaf a | Branch (Tree a) (Tree a)
For example, I implemented traversal of the tree:
treeFoldt :: Tree t -> [t]
treeFoldt = foldt1 (:) []
It works pretty good. But I want to implement Foldable
interface.
I think, that I should write something like that:
instance Foldable Tree where
foldr = treeFoldt
But it does not work. How can I fix this?
A fold takes a binary function, a starting value (I like to call it the accumulator) and a list to fold up. The binary function itself takes two parameters. The binary function is called with the accumulator and the first (or last) element and produces a new accumulator.
foldMap is similar to fold but maps every A value into B and then combines them using the given Monoid[B] instance.
I could try to tell you where the problem with your code is but sadly you did not give the definition for foldt1
But this should work (if your implementation of treeFoldt
is ok - remember: []
is an instance of Foldable
):
instance Foldable Tree where
foldr f s = Data.Foldable.foldr f s . treeFoldt
Monoid
Anyway, I think the easiest way in this case is to implement just the foldMap
part:
import Data.Foldable
import Data.Monoid
data Tree a = Leaf a | Branch (Tree a) (Tree a)
instance Foldable Tree where
foldMap f (Leaf a) = f a
foldMap f (Branch l r) = foldMap f l `mappend` foldMap f r
and this surely works.
λ> let t = Branch (Branch (Leaf $ Sum 2) (Leaf $ Sum 4)) (Leaf $ Sum 6)
λ> fold t
Sum {getSum = 12}
or
λ> let t = Branch (Branch (Leaf 2) (Leaf 4)) (Leaf 6)
λ> foldMap Sum t
Sum {getSum = 12}
and of course you don't need the Monoid
part at all - the default implementations work just fine:
λ> Data.Foldable.foldr1 (+) t
12
by the way: it's most likely not obvious how foldr1 (+)
can be expressed just in terms of foldMap
and it's a nice (advanced) exercise to try to do it on your own :D
I think Foldable and Traversable by A. Arnold is quite a nice blog post on Foldable
(and Traversable
) in general - maybe you find it helpful too
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With