Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why "fmap (replicate 3) Just" has a type of "a -> [Maybe a]", In Haskell

Recently I am learning Haskell online with Learn You a Haskell for Great Good.

I have two questions:

  1. fmap (replicate 3) is of type Functor f=> f a -> f [a]. Why can it be applied to Just?

  2. Furthermore, why is fmap (replicate 3) Just of type a -> [Maybe a], and not of type a -> Maybe [a]?

like image 958
Guocheng Avatar asked Jun 03 '14 02:06

Guocheng


1 Answers

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 ..

like image 166
bheklilr Avatar answered Jan 04 '23 19:01

bheklilr