Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

On a Functor instance declaration

Tags:

haskell

This loads without error:

data Const c a = Const c

instance Functor (Const c) where
    fmap _ (Const v) = Const v

...but this

data Const' c a = Const' c

instance Functor (Const' c) where
    fmap _ cv = cv

...fails with:

    Couldn't match type `a' with `b'
      `a' is a rigid type variable bound by
          the type signature for fmap :: (a -> b) -> Const' c a -> Const' c b
          at test.hs:4:5
      `b' is a rigid type variable bound by
          the type signature for fmap :: (a -> b) -> Const' c a -> Const' c b
          at test.hs:4:5
    Expected type: Const' c b
      Actual type: Const' c a
    In the expression: cv
    In an equation for `fmap': fmap _ cv = cv
    In the instance declaration for `Functor (Const' c)'

I don't understand the error. Why can't the compiler infer that the type of cv is Const' c? What else could it be, given the rest of the declaration, and the definition of fmap?

like image 530
kjo Avatar asked Sep 17 '15 23:09

kjo


2 Answers

If you want to be fully explicit, you can write

{-# LANGUAGE ScopedTypeVariables, InstanceSigs #-}

data Const c a = Const c

instance Functor (Const c) where
    fmap :: forall a b. (a -> b) -> Const c a -> Const c b
    fmap _ (Const v :: Const c a) = Const v :: Const c b

Which is a bit of a mouthful. :-)

forall a b. brings a and b into scope so they can be referred to in the definition. This is enabled by ScopedTypeVariables. InstanceSigs allows us to write the signature of fmap in the first place (normally it must be inferred from the class, so we have nowhere to get the type variable names from).

like image 168
luqui Avatar answered Nov 28 '22 23:11

luqui


cv is of type Const' c a, so it can't also be of type Const' c b (unless a ~ b). Const v and Const v, however, can be of different types.

Another way of looking at it is that fmap _ cv = cv is equivalent to fmap _ = id, which would be of type Const' c a -> Const' c a, but fmap _ must be of type Const' c a -> Const' c b.

like image 30
Rein Henrichs Avatar answered Nov 28 '22 23:11

Rein Henrichs