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
?
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).
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With