Why "fmap (replicate 3) Just" has a type of "a -> [Maybe a]", In Haskell
functor, haskell, types
Solution
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 `.`.
Problem
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]`?