In LYAH, there is a piece of code that looks like this.
data Tree a = Empty | Node a (Tree a) (Tree a) deriving (Show, Read, Eq)
instance F.Foldable Tree where
foldMap f Empty = mempty
foldMap f (Node x l r) = F.foldMap f l `mappend`
f x `mappend`
F.foldMap f r
ghci> F.foldl (+) 0 testTree
42
ghci> F.foldl (*) 1 testTree
64800
As far as I know, foldMap is of type foldMap :: (Monoid m, Foldable t) => (a -> m) -> t a -> m, but Num a => a itself is not of type Monoid, so I am wondering how does Foldable.foldl actually work here? And since foldMap is called internally by Foldable.foldl, what is the type of the Monoid?
It's a bit easier to figure out if you consider foldr, which has the type (a -> b -> b) -> b -> t a -> b. The 'algebra' function has the type a -> b -> b, which you can view as a -> (b -> b) - that is: a function that takes a as input, and returns b -> b as output.
Now, b -> b is an endomorphism, which is also a monoid, and Data.Monoid defines a type Endo a (or here, it ought perhaps to be Endo b), which is, indeed, a Monoid.
foldr simply uses Endo internally to call foldMap:
foldr :: (a -> b -> b) -> b -> t a -> b
foldr f z t = appEndo (foldMap (Endo #. f) t) z
foldl basically just flips the arguments around in order to do the same trick:
foldl :: (b -> a -> b) -> b -> t a -> b
foldl f z t = appEndo (getDual (foldMap (Dual . Endo . flip f) t)) z
To be clear, I literally copied these two function implementation from the Haskell source. If you go to the documentation of Data.Foldable, there are various links to view the source. That's what I did.
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