Declaring type class instance for composition of constructors

Viewed 144

In trying to answer this SO question i wondered:

Suppose I want to be able to write fmap (+1) [Just 2] instead of (fmap.fmap) (+1) [Just 2] (after all, the composition of two functors is another functor)

I then could try and declare a Functor instance for the composition of [] and Maybe (i.e. two constructors with kind * -> *)

instance Functor ..eh??? where 
  fmap f [Nothing] = [Nothing]
  fmap f [] = []
  -- ...etc.

However, without a type-level lambda (\Lambda a -> [Maybe a] :: * -> *) I don't see how to write the instance declaration part:

instance Functor Maybe([]) 

is nonsense, and doens't even kind check, of course.

Is there any way around this? Of course, if the constructors happen to be monads (like in this case) I could use monad transformers (i.e. constructors of kind * -> * -> * ), and the composition would become an application like ListT Maybe, which is perfectly legal. However, that is not the case generally.

2 Answers

With Data.Functor.Compose we can write

> fmap (+1) $ Compose [Just 2]
=> Compose [Just 3]

and further with coerce,

> coerce . fmap (+1) . Compose $ [Just 2] :: [Maybe Integer]
=> [Just 3]

I upvoted and accepted Will Ness's answer. However, it is important to note that, even though Compose is a submodule of Data.Functor and its Hackage blurb says Composition of functors, there is nothing Functor-specific about the definition of Compose, so the solution will work with any arbitrary type class:

class Blurgh f where 
   b : f a -> f a 

instance Blurgh (Compose [] Maybe) where ...

> (coerce . b . Compose)  [Just 2] :: [Maybe Integer]
Related