Recently I am learning Haskell online with Learn You a Haskell for Great Good.
I have two questions:
fmap (replicate 3)
is of type Functor f=> f a -> f [a]
. Why can it be applied to Just
?
Furthermore, why is fmap (replicate 3) Just
of type a -> [Maybe a]
, and not of type a -> Maybe [a]
?
This is easy to understand if you realize that what you're fmap
-ing over is a function, not a Maybe a
value. The type of Just
is a -> Maybe a
, so it falls in the (->) a
functor, not the Maybe
functor. The instance of Functor
for functions looks like
instance Functor ((->) a) where
fmap g f = g . f
so fmap
just becomes normal function composition! This means that
fmap (replicate 3) Just
is the same as
replicate 3 . Just
which quite clearly has the type a -> [Maybe a]
A more "type algebra" explanation would be to line up the types and substitute until you can't anymore. Let's start with our types, but with different variable names to make it easier to follow:
fmap :: Functor f => (a -> b) -> (f a -> f b)
replicate :: Int -> c -> [c]
Just :: x -> Maybe x
Then for fmap (replicate 3)
:
(replicate 3) :: c -> [c]
fmap :: (a -> b) -> (f a -> f b)
So
(c -> [c]) ~ (a -> b)
Which implies
c ~ a
[c] ~ b
b ~ [a]
So substituting back in:
fmap (replicate 3) :: f c -> f [c]
Then what we're fmap
-ing over is Just
, which has the type
Just :: x -> Maybe x
Which can be rewritten in prefix form as
Just :: (->) x (Maybe x)
Or with more parentheses if we really want
Just :: ((->) x) (Maybe x)
Then
Just :: ((->) x) (Maybe x)
fmap (replicate 3) :: f c -> f [c]
Which implies
((->) x) (Maybe x) ~ f c
(->) x ~ f
Maybe x ~ c
[c] ~ [Maybe x]
So substituting back in:
fmap (replicate 3) :: ((->) x) (Maybe x) -> ((->) x) [Maybe x]
And back to infix notation
fmap (replicate 3) :: (x -> Maybe x) -> (x -> [Maybe x])
Then applying Just
:
fmap (replicate 3) Just :: x -> [Maybe x]
I would like to stress here that Maybe
being a Functor
has nothing to do with this reduction, the only Functor
involved is the function Functor
. Lists are also a Functor
, but just because it appears in the type of replicate
doesn't mean it matters in this case. It is rather easy to get confused with the function
fmap (replicate 3) . Just :: a -> Maybe [a]
but that's entirely different due to the addition of the .
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With