I'm trying to figure out if it's possible (and how) to define class instances for multi-parameter type synonyms.
For example:
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-}
type F a b = a -> b
data DF a b = DF (a -> b)
class C c a b where
doc :: c a b -> a -> b
It works for a multi-param type instance:
instance C DF a b where
doc (DF f) x = f x
But it doesn't work for type synonyms:
-- ERROR:
--
-- Type synonym `F' should have 2 arguments, but has been given none
-- In the instance declaration for `C F a b'
--
instance C F a b where
doc f x = f x
Is it possible to define a type class instance for F
?
It's not possible as written. Type synonyms must in general be fully applied to use them, especially as a type class parameter.
Note that if you can eta-reduce the type synonym enough an instance is possible; it's the synonym which must be fully applied, not the type it refers to. So this would work:
type F = (->)
instance C F a b where
doc f x = f x
There is a LiberalTypeSynonyms
extension that relaxes some of the rules about expanding type synonyms, but it doesn't help here--it only lets you do things like give a partially-applied type synonym as a type parameter of another type synonym. Everything must still be fully expanded to use otherwise.
To see one reason why this restriction is necessary, consider the following type synonym:
type Flip f a b = f b a
And the following instance:
instance Functor (Flip Either a) where
fmap _ (Right x) = Right x
fmap f (Left x) = Left (f x)
Recall that there's also an instance Functor (Either a)
which does the same thing, except mirrored. Both are sensible Functor
instances.
Keeping in mind that unlike newtype
, type synonyms are considered the same as the type they refer to, what should the value of the expression fmap not (Right True :: Either Bool Bool)
be?
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