I am a beginner to Haskell. I know that the function fmap
takes two arguments ((a->b) -> f a ->
) and returns a functor (f b
), but I cannot understand the following lambda expression
*Main> :t \g x -> fmap ($) g x
\g x -> fmap ($) g x :: (t -> a -> b) -> t -> a -> b
where is the functor?
Btw, I have tried several similar expression with different brackets, which give different results:
*Main> :t \g x -> fmap ($) (g x)
\g x -> fmap ($) (g x) :: Functor f => (t -> f (a -> b)) -> t -> f (a -> b)
*Main> :t \g x -> fmap $ g x
\g x -> fmap $ g x :: Functor f => (t -> a -> b) -> t -> f a -> f b
I don't understand this.
CodePudding user response:
From
\g x -> fmap ($) g x :: (t -> a -> b) -> t -> a -> b
we have
g :: t -> a -> b
x :: t
fmap ($) g :: t -> a -> b
fmap ($) g x :: a -> b
To find the functor, it suffices to write the type of g
as the type-level application F X
for some F
and X
.
We have
t -> a -> b = (->) t (a -> b)
hence, F = (->) t
and X = (a -> b)
.
Therefore, the fmap
call works in the (->) t
functor. We need to think to t -> a -> b
as a value of type a -> b
"wrapped" under the functor (->) t
.
Now, we have
($) :: (a->b) -> a -> b
-- which means
($) :: (a->b) -> (a -> b)
g :: F (a->b)
fmap ($) :: F (a->b) -> F (a->b)
fmap ($) g :: F (a->b)
-- i.e.
fmap ($) g :: t -> (a->b)
CodePudding user response:
First, we have, as you said,
fmap :: Functor f
=> ( a -> b ) -> f a -> f b
($) :: (t->s) -> t -> s
g :: f a
~ f (t->s)
----------------------------------------- a ~ (t->s) ~ b
fmap ($) g :: f b
~ f (t->s)
and then this is applied to an x
... but only functions get applied to arguments:
fmap ($) g :: Functor f => f (t->s)
~ Functor ((->) c) => c -> (t->s)
x :: c
---------------------------------------------- f ~ ((->) c)
fmap ($) g x :: (t->s)
and indeed ((->) c)
is a functor. So the application to an x
is what selects a specific Functor type, the Functor of functions.
Putting it all together,
-- g x
\g x -> fmap ($) g x :: (c -> (t->s)) -> c -> (t->s)
-- compare with
fmap ($) :: f (t->s) -> f (t->s) -- Functor (f ~ ((->) c)
fmap id :: f q -> f q
id :: r -> r
Indeed ($)
is just a more specialized id
, and fmap id === id
, by the Functor Laws. The type just gets more specialized because of all the extra arguments / instantiations giving more context to it.