I’m playing a bit with MonadTrans
and MFunctor
from mmorph
.
I defined a class Embeds
and I’m trying to define the following instances
instance {-# OVERLAPPABLE #-} (Monad m, MonadTrans t, Embeds n m) => Embeds n (t m)
instance {-# OVERLAPPING #-} (Monad n, MFunctor t, Embeds n m) => Embeds (t n) (t m)
When I try to use those instances, I get the following error
Overlapping instances for Embeds
(StateT Int Identity) (StateT Int IO)
arising from a use of ‘embed’
Matching instances:
instance [overlapping] forall k (n :: * -> *)
(t :: (* -> *) -> k -> *) (m :: * -> *).
(Monad n, MFunctor t, Embeds n m) =>
Embeds (t n) (t m)
-- Defined at Main.hs:30:30
instance [overlappable] (Monad m, MonadTrans t, Embeds n m) =>
Embeds n (t m)
-- Defined at Main.hs:25:31
An overlapping instance can only be chosen when it is strictly more specific.
The first instance that follows overlaps the second, but is not more specific than it:
instance [overlapping] forall k (n :: * -> *)
(t :: (* -> *) -> k -> *) (m :: * -> *).
(Monad n, MFunctor t, Embeds n m) =>
Embeds (t n) (t m)
instance [overlappable] (Monad m, MonadTrans t, Embeds n m) =>
Embeds n (t m)
I would say that Embeds (t n) (t m)
is strictly more specific than Embeds n (t m)
. Are also constraints considered when checking if a type is stricter than another?
Is there a way to say that I always want to use the second instance when both are available?
As a related question… if I use {-# INCOHERENT #-}
for both instances, the code compiles correctly. Is that a safe/wise thing to do?
You can find the complete code here