The simple definition of function composition is:
f ( g x)
or
(f . g) $ x
Now I have following example:
newtype Compose f g a =
Compose { getCompose :: f (g a) }
deriving (Eq, Show)
instance (Functor f, Functor g) => Functor (Compose f g) where
fmap f (Compose fga) = Compose $ (fmap . fmap) f fga
Then I try to write fmap without composition operator as:
instance (Functor f, Functor g) => Functor (Compose f g) where
fmap f (Compose fga) = Compose $ fmap f (fmap f fga)
and the compiler complains:
* Couldn't match type `b' with `g b'
`b' is a rigid type variable bound by
the type signature for:
fmap :: forall a b. (a -> b) -> Compose f g a -> Compose f g b
at D:\haskell\chapter25\src\Twinplicative.hs:11:5
Expected type: f (g b)
Actual type: f b
* In the second argument of `($)', namely `fmap f (fmap f fga)'
In the expression: Compose $ fmap f (fmap f fga)
In an equation for `fmap':
fmap f (Compose fga) = Compose $ fmap f (fmap f fga)
* Relevant bindings include
fga :: f (g a)
(bound at D:\haskell\chapter25\src\Twinplicative.hs:11:21)
f :: a -> b
(bound at D:\haskell\chapter25\src\Twinplicative.hs:11:10)
fmap :: (a -> b) -> Compose f g a -> Compose f g b
(bound at D:\haskell\chapter25\src\Twinplicative.hs:11:5)
How to compose fmap above without composition operator?
2 Answers 2
The function you provide to the leftmost application of fmap should have type g a -> g b while you are providing f which has type a -> b. You can lift a function a -> b to g a -> g b using fmap i.e. fmap f. The second argument to the outer fmap should have type f (g a) which is the type of fga:
instance (Functor f, Functor g) => Functor (Compose f g) where
fmap f (Compose fga) = Compose $ fmap (fmap f) fga
Comments
I like Lee's answer, which states clearly how you could implement the Functor instance for Compose yourself from scratch. However, I also thought it worth answering a closely related question, which is: how do I start from the existing instance and mechanically rewrite it to avoid the (.) function composition? Therefore I tackle that question in this answer.
Since (f . g) x = f (g x) is the defining equation of (.), we conclude (fmap . fmap) f = fmap (fmap f). Applying both sides of the equation to fga, we get:
(fmap . fmap) f fga = fmap (fmap f) fga
fmap f (Compose fga) = Compose $ fmap (fmap f) fga