Reputation: 3387
I am confused about the result of this expression:
fmap (*) 3
Which produces type:
fmap (*) 3 :: (Functor f, Num a, Num (f a)) => f (a -> a)
What I was expecting is that the result would be the same as doing:
(*) 3
Which produces a 1-parameter function:
Prelude> (*) 3 $ 10
30
I was expecting that fmap
would apply 3
to (*)
producing (*3)
, but the following produces an error:
Prelude> (fmap (*) 3) 10
<interactive>:201:1:
Non type-variable argument in the constraint: Num (a -> a)
(Use FlexibleContexts to permit this)
When checking that `it' has the inferred type
it :: forall a a1. (Num a, Num a1, Num (a1 -> a)) => a -> a
What type of parameter is the result of (fmap (*) 3)
expecting?
Upvotes: 0
Views: 136
Reputation: 52039
The key is here:
fmap (*) 3 :: (Functor f, Num a, Num (f a)) => f (a -> a)
^^^^^^^^^
In Haskell numeric literals are overloaded, so 3
could have any type b
as long as b
has a Num
instance.
The compiler goes through the following analysis:
b
with constraint Num b
fmap
has type Functor f => (a -> c) -> f a -> f c
*
has type a -> c
and 3 has type f a
*
has type Num a => a -> a -> a
so c
= a -> a
, and a
has constraint Num a
b
= f a
from (1) and (2)Gathering up all of the constraints and equivalences:
fmap (*) 3 :: ( Functor f, -- by (2)
Num a, -- by (4)
Num (f a) -- by (1) and (5)
) => f ( a -> a ) -- by (2) and c = a -> a
Update:
You asked for an example where fmap (*) 3
makes sense. What is problematic here is that (*)
has arity 2 and fmap
is usually used with a function of a single argument (arity 1). For instance:
fmap (+1) (Just 3) = Just 4
fmap (+1) Nothing = Nothing
fmap (*6) [1,2,3] = [6,12,18]
fmap words getLine = do x <- getLine; return (words x)
Note: (+1)
is just the "add 1" function, e.g. \x -> x+1
, and (*6)
is just the multiply by 6 function, e.g. \x -> x*6
.
So fmapping (*) :: Int -> Int -> Int
is somewhat unusual. Of course, we can interpret the type of (*)
to be Int -> (Int -> Int)
which gives it arity 1, but then dealing with functors of functions is getting into a level of abstraction that we don't normally deal with.
Upvotes: 9