simkestuff
simkestuff

Reputation: 55

How function signature matches requested types

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

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

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 Ints. 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

Related Questions