2
votes

I just finished chapter 11 of the Learn You A Haskell For Great Good and I would like to have a better understanding of Applicative Functors before moving on. I have the following ghci code.

let a = Just (5+) -- Instead of mapping + to Just 5
let b = (3+) <$> a -- I imported Control.Applicative even though most of these modules are deprecated
let c = Just (3+) <*> a -- I expect this to be equivalent to b and :t b, :t c shows that they are the 'same'
a <*> Just 1 -- returns 6 as I expected

Now I expect b and c to be: Just ((3+) . (5+)) which means that I could do:

b <*> Just 1 -- and get 9 as in (3+) $ (5+) 1 or ((3+) . (5+)) 1

But I get: No instance for (Num (b0 -> b0)) arising from a use of 'it' In a stmt of an interactive GHCI command: print it.

Question 1: what does the restriction as seen in the following imply:

b :: (Num (a -> a), Num a) => Maybe (a -> a)

I thought that just means that <*> can "extract" the (a -> a) from 'b'. In my noob mind I know that Num a means that 'a' must be an instance of Num but Num (a -> a) is not making much sense to me. Does it mean that the (a -> b) inside the Maybe must return an instance of Num?

Question 2: Isn't everything I've done feasible in the Applicative realm? Is there any obvious ways to print or see the result of 'b <*> Just 1'?

let Just val = b <*> Just 1
:t val -- returns ((Num (t -> t), Num t) => t which tells me that val is an instance of Num but then again I am just a beginner so what do I know?

Note: I have snapshots of my ghci session and can add them if necessary. I read some related posts but nothing seems to enlighten me.

1
I just tried to put your first code lines into my ghci, but the declaration of b threw an error already. Maybe you should indicate the version of ghc you are using, and/or try to get the newest version first.Magnus
@Magnus GHCi, version 7.8.3Buckeye14Guy

1 Answers

10
votes

When you write (expanded)

let b = (3+) <$> Just (5+)

The resulting value, by definition of <$> (which is just fmap!) is:

Just (3 + (5+))

You're adding a number to a function! This is why you get weird type errors.

Specifically, Haskell is trying desperately to pretend (5+) is a number:

b :: (Num (a -> a), Num a) => Maybe (a -> a)

It's saying, if there is some crazy type a for which a and (a -> a) are both instances of Num, I could add them together inside the Functor as though they were numbers, and give you a resulting Maybe (a -> a)! Generally, however, functions aren't instances of the Num typeclass, so everything blows up.

You meant to write:

let b = ((3+).) <$> Just (5+)

Which indeed works as you expected (b <*> Just 1 == Just 9).