Can someone explain what the type mean and how to implement this?
class Foldable f where
foldMap :: (Monoid m) => (a -> m) -> f a -> m
Based on https://hackage.haskell.org/package/base-4.9.1.0/docs/Data-Foldable.html#v:foldMap, they explained it as "Map each element of the structure to a monoid, and combine the results." but I don't quite understand what it means. How can I map an element to the structure of a Monoid?
I tried
foldMap f = mconcat . (<$>) f
but I got this error:
• Couldn't match type ‘f’ with ‘[]’
‘f’ is a rigid type variable bound by
the class declaration for ‘Foldable’
at traversable.hs:41:16
Expected type: f a -> m
Actual type: [a] -> m
• In the expression: mconcat . (<$>) f
In an equation for ‘foldMap’: foldMap f = mconcat . (<$>) f
• Relevant bindings include
foldMap :: (a -> m) -> f a -> m (bound at traversable.hs:45:3)
I tried @WillemVanOnsem's code and got this error:
error:
• Could not deduce (Data.Foldable.Foldable f)
arising from a use of ‘foldr’
from the context: Foldable f
bound by the class declaration for ‘Foldable’
at traversable.hs:41:7-14
or from: Monoid m
bound by the type signature for:
foldMap :: forall m a. Monoid m => (a -> m) -> f a -> m
at traversable.hs:42:14-47
Possible fix:
add (Data.Foldable.Foldable f) to the context of
the type signature for:
foldMap :: forall m a. Monoid m => (a -> m) -> f a -> m
or the class declaration for ‘Foldable’
• In the expression: foldr (\ x -> mappend (f x)) mempty
In an equation for ‘foldMap’:
foldMap f = foldr (\ x -> mappend (f x)) mempty
they explained it as "Map each element of the structure to a monoid, and combine the results." but I don't quite understand what it means. How can I map an element to the structure of a Monoid?
We do that with the function with signature a -> m
. So we define the "mapping" function ourself.
A monoid [wiki] is an algebraic structure. It is in essence a 3-tuple (S, ⊕, s0) where S is the set of values, ⊕ :: S × S → S is an associative binary operator, and s0 is an identity element, such that s0 ⊕ s = s ⊕ s0 = s.
Types that are members of the Foldable
class are data structures that can be "folded". It means that if you for example have a Tree
that contains Int
s, so a Tree Int
, such that you, for a function f :: Int -> Int -> Int
, and a neutral element z
, you can derive an Int
.
By using foldMap
we will call a function f :: a -> m
on these elements, and use the monoid function ⊕ to "fold" the values. For data structures that implement Functor
as well, it is thus, more or less equivalent to foldMap f = foldr mappend mempty . fmap f
.
We can however use the f
in the foldr
function itself, like:
foldMap' :: (Foldable f, Monoid m) => (a -> m) -> f a -> m
foldMap' f x = foldr (\y -> mappend (f y)) mempty x
or shorter:
foldMap' :: (Foldable f, Monoid m) => (a -> m) -> f a -> m
foldMap' f = foldr (mappend . f) mempty
Here we thus first pre-process the values in the datastructure with f
to convert these to a monoid object, and we call mappend
as folding function on these items.