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 fs 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