Search code examples
haskellfunctor

How (fmap . fmap) typechecks


I have been going through a article(http://comonad.com/reader/2012/abstracting-with-applicatives/) and found the following snippet of code there:

newtype Compose f g a = Compose (f (g a)) deriving Show

instance (Functor f, Functor g) => Functor (Compose f g) where
    fmap f (Compose x) = Compose $ (fmap . fmap) f x

How does actually (fmap . fmap) typechecks ?

Their types being:

(.)  :: (a -> b) -> (r -> a) -> (r -> b)
fmap :: (a -> b) -> f a -> f b
fmap :: (a -> b) -> f a -> f b

Now from here I can see in no way in which fmap . fmap will typecheck ?


Solution

  • First let's change the type variables' names to be unique:

    (.)  :: (a -> b) -> (r -> a) -> (r -> b)
    fmap :: Functor f => (c -> d) -> f c -> f d
    fmap :: Functor g => (x -> y) -> g x -> g y
    

    Now the first parameter to . has type a -> b and we supply an argument of type (c -> d) -> (f c -> f d), so a is c -> d and b is f c -> f d. So so far we have:

    (.) :: Functor f => -- Left operand
                        ((c -> d) -> (f c -> f d)) ->
                        -- Right operand
                        (r -> (c -> d)) ->
                        -- Result
                        (r -> (f c -> f d))
    

    The second parameter to . has type r -> a a.k.a. r -> (c -> d) and the argument we give has type (x -> y) -> (g x -> g y), so r becomes x -> y, c becomes g x and d becomes g y. So now we have:

    (.)       :: (Functor f, Functor g) => -- Left operand
                                           ((g x -> g y) -> (f (g x) -> f (g y))) -> 
                                           -- Right operand
                                           ((x -> y) -> (g x -> g y)) ->
                                           -- Result
                                           (x -> y) -> f (g x) -> f (g y)
    fmap.fmap :: (Functor f, Functor g) => (x -> y) -> f (g x) -> f (g y)