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]`?

Original source