fmap
applies a function to values found in some functorial value. In fmap ($ 3) [(4+), (10*), (^2), sqrt]
, the list is the functorial value, and the function ($ 3)
is applied to its elements. As for fmap ($ 3) (4+)
, leftaroundabout correctly points out that:
However, (4+)
by itself is not a function wrapped in any functor, it's just a function by itself.
In this case, there is a complementary way to look at it. (4+)
is a functorial value; however, the functor isn't the one you need. Functions are functors, and, for the purposes of fmap
, the values "found in them" are the results of the function:
GHCi> :set -XTypeApplications
GHCi> :t fmap @((->) _)
fmap @((->) _) :: (a -> b) -> (w -> a) -> w -> b
fmap
for functions applies a function to the results of another function, which amounts to function composition. So this...
GHCi> fmap (4*) (2+) 1
12
... is the same as:
GHCi> ((4*) . (2+)) 1
12
In your case, we have:
GHCi> :t (4+)
(4+) :: Num a => a -> a
So fmap f (4+)
will apply f
to the Num a => a
result of (4+)
. The type of ($ 3)
, though, is:
GHCi> :t ($ 3)
($ 3) :: Num a => (a -> b) -> b
And so fmap ($ 3)
will expect a functorial value with functions to be possibly found in it:
GHCi> :t fmap ($ 3)
fmap ($ 3) :: (Num a, Functor f) => f (a -> b) -> f b
Putting it all together, we get:
GHCi> :t fmap ($ 3) (4+)
fmap ($ 3) (4+) :: (Num (a -> b), Num a) => (a -> b) -> b
The type error this will lead to has to do with the Num (a -> b)
constraint. If there are functions to be found in (4+)
, then 4
itself must be a function. As 4
is a numeric literal, its type must be also an instance of Num
. However, there is no Num
instance for functions. Trying fmap ($ 3) (4+)
leads to an error which mentions Num (a -> b)
. That should suggest something is off:
GHCi> fmap ($ 3) (4+)
<interactive>:33:1: error:
* Non type-variable argument in the constraint: Num (a -> b)
(Use FlexibleContexts to permit this)
* When checking the inferred type
it :: forall a b. (Num (a -> b), Num a) => (a -> b) -> b
The "Non-type variable argument" complaint, though, is a bit of a distraction, induced by numeric literals being polymorphic. We can get a more straightforward error either by enabling FlexibleContexts
and then trying to use fmap ($ 3) (4+)
(which will lead to Num a => a
being specialised to Integer
thanks to the defaulting rules)...
GHCi> :set -XFlexibleContexts
GHCi> fmap ($ 3) (4+) (2*)
<interactive>:39:1: error:
* No instance for (Num (Integer -> Integer))
arising from a use of `it'
(maybe you haven't applied a function to enough arguments?)
* In the first argument of `print', namely `it'
In a stmt of an interactive GHCi command: print it
... or by specialising the numeric type through a type annotation:
GHCi> fmap ($ 3) ((4 :: Integer)+)
<interactive>:42:13: error:
* Couldn't match type `Integer' with `Integer -> b'
Expected type: Integer -> Integer -> b
Actual type: Integer -> Integer
* In the second argument of `fmap', namely `((4 :: Integer) +)'
In the expression: fmap ($ 3) ((4 :: Integer) +)
In an equation for `it': it = fmap ($ 3) ((4 :: Integer) +)
* Relevant bindings include
it :: Integer -> b (bound at <interactive>:42:1)