1
votes

I'm stuck with Functor instance for composition of other functors in haskell.

data Cmps f g x = Cmps {getCmps :: f (g x)} deriving (Eq,Show) 

--
instance (Functor f, Functor g) => Functor (Cmps f g) where
  -- fmap :: (a -> b) -> (Cmps f g) a -> (Cmps f g) b
  fmap = ?

In GHC.Generics functor just derived with {-# LANGUAGE DeriveFunctor #-}

-- | Composition of functors
infixr 7 :.:
newtype (:.:) f (g :: * -> *) (p :: *) = Comp1 { unComp1 :: f (g p) }
  deriving (Eq, Ord, Read, Show, Functor, Generic, Generic1)`

I can't get some like fmap h (Cmps f g x) = Cmps f g (h x) becouse of error The constructor ‘Cmps’ should have 1 argument, but has been given 3, and something like fmap h (f (g x)) don't work too. How can I get f, g and x from Cmps type in fmap implementation?

1
You are using Cmps like it has three fields, but it only has one, of type f (g x). so the left hand side should look like fmap f (Cmps x) = ... try again with that in mind. You can also see the instance GHC generates using DeriveFunctor with the -ddump-deriv option. - Li-yao Xia
I have moved your solution to an answer proper. For your future questions, note that it is perfectly fine to answer your to own question. - duplode

1 Answers

1
votes

Consolidating the remarks by Li-yao Xia and orlan as an answer.

In your Cmps definition...

data Cmps f g x = Cmps {getCmps :: f (g x)} deriving (Eq,Show)

... f, g and x are type variables; they do not stand for fields. Cmps has a single field, of type f (g x). Accordingly, the fmap implementation for it should be:

instance (Functor f, Functor g) => Functor (Cmps f g) where
  -- fmap :: (a -> b) -> (Cmps f g) a -> (Cmps f g) b
  fmap h (Cmps x) = Cmps (fmap (fmap h) x)

If you want to compare that with an equivalent instance in the core libraries which is not derived, have a look at Compose from Data.Functor.Compose.