Reputation: 55
Im trying to understand how this works; In GHCi:
foldMap (+3) (Just 5) :: Sum Int
produce result
Sum {getSum = 8}
Now, type of foldMap is
foldMap :: (Foldable t, Monoid m) => (a -> m) -> t a -> m
and from that type signatures for function used by foldMap do not match with signature of used function (+3):
(+3) :: Num a => a -> a
vs
f :: Monoid m => a -> m
If I also try something like this:
foldMap _ (Just 5) :: Sum Int
---------------------------------------
<interactive>:113:9: error:
* Found hole: _ :: Integer -> Sum Int
* In the first argument of `foldMap', namely `_'
In the expression: foldMap _ (Just 5) :: Sum Int
....
this also show that expected function is of signature :: (Integer -> Sum Int)
and which is consistent with signature in foldMap declaration but not consistent with (+3) which is used above? My understanding of foldMap is that it apply function which turn every element of Foldable instance into Monoid which is then possible to collapse into single values.
I assume that compiler infere what types should be (in line above it is explicitly stated) but what I don't understand is how does compiler "adjust" types signature of function (+3) so that first line compile?
Upvotes: 4
Views: 90
Reputation: 477533
In short: since instance Num a => Num (Sum a)
holds, your 5
is seen as a Sum Int
.
Given a
is a Num
type, Sum a
, is a Num
type as well. Indeed, in the documentation we see:
Num a => Num (Sum a)
Now a Num
type n
has a function fromInteger :: Integer -> n
to transform an Integer
into that number type n
. The idea is that if you thus write 5
, you implicitly write something like fromInteger 5
.
By writing
foldMap (+3) (Just 5) :: Sum Int
with foldMap :: (Foldable f, Monoid m) => (a -> m) -> t a -> m
we thus know that m
should be a Sum Int
, that t ~ Maybe
, and since (+3) :: Num a => a -> a
, it means that m ~ a ~ Sum Int
. It thus means that the 5
(from Just 5
) and 3
(from (+3)
) are Sum Int
s. The 5
you have written is thus interpreted as a Sum 5
. The same holds for 3
.
So now that we know that we actually have written:
foldMap (+ (Sum 3)) (Just (Sum 5)) :: Sum Int
The foldMap
will map every element of the structure to a monoid (well it is already a monoid, but it will increment them with 3
anyway), and then perform a fold. So that means we have written something like:
(+ (Sum 3)) (Sum 5) <> mempty
For the Num n => Sum n
types the mempty
is Sum 0
, so that means we wrote:
(+ (Sum 3)) (Sum 5) <> (Sum 0)
and (<>)
for a Sum
is the (+)
, so it means the expression boils down to:
(+ (Sum 3)) (Sum 5) + (Sum 0)
which can be evaluated to:
(Sum 5 + Sum 3) + Sum 0
or:
Sum 8
Upvotes: 6