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