I'm trying to write an Eq
instance for an EitherT
newtype given by:
newtype EitherT e m a = EitherT { runEitherT :: m (Either e a) }
I assumed the following Eq
instance would work:
instance (Eq e, Eq a, Eq m) => Eq (EitherT e m a) where
a == b = (runEitherT a) == (runEitherT b)
However, I'm seeing an error:
Expected kind '* -> *', but 'm' has kind '*'
What I'm reading from that error is that my typeclass constraint ( ... Eq m) => ...
is confusing the compiler into thinking that I believe m
to be of kind *
, when my newtype declaration for EitherT
expects it to be of kind * -> *
.
I'm wondering what I need to do, to declare that I want an Eq
instance for some higher kinded type m
to implement Eq
for my EitherT
newtype.
Edit: As pointed out by @AlexisKing, I can get this to work with:
{-# LANGUAGE UndecideableInstances #-}
instance (Eq (m (Either e a))) => Eq (EitherT e m a) where
a == b = (runEitherT a) == (runEitherT b)
However, it seems strange to me to that a language extension is required to write this Eq
instance. Is there no other way to express such a typeclass constraint in vanilla Haskell? If not, why?
You're looking for Eq1
which is in Data.Functor.Classes
since base 4.9.0.0. Before that it was in one of the -extras
packages or transformers
? (it's in transformers now since 0.4.0.0)
Eq1 f
says that you can compare f
s as long as you have a way to compare their contents
class Eq1 f where
liftEq :: (a -> b -> Bool) -> f a -> f b -> Bool
In your case you'd use it like
instance (Eq e, Eq1 m) => Eq1 (EitherT e m) where
liftEq f a b = liftEq (liftEq f) (runEitherT a) (runEitherT b)
The liftEq f
is to use the existing Eq1
instance for Either
.
And can define an Eq
instance as
instance (Eq e, Eq a, Eq1 m) => Eq (EitherT e m a) where
(==) = liftEq (==)
The old Eq1
was
class Eq1 f where
eq1 :: (Eq a) => f a -> f a -> Bool
In your case you'd use it like
instance (Eq e, Eq1 m) => Eq1 (EitherT e m) where
eq1 a b = eq1 (runEitherT a) (runEitherT b)
instance (Eq e, Eq a, Eq1 m) => Eq1 (EitherT e m) where
a == b = eq1 (runEitherT a) (runEitherT 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