问题
I want to make my monad transformer to be an instance of MonadError
if the transformed monad is an instance. Basically I want my transformer to behave as the built-in transformers do, for example there is a MonadError
instance for StateT
:
MonadError e m => MonadError e (StateT s m)
I tried doing this:
instance MonadError e m => MonadError e (MyMonadT m)
But GHC started complaining about undecidable instances, apparently the MTL library just enables undecidable instances, but is there any way to avoid that? Or it is OK in this case and it won't cause any problems?
回答1:
This is basically fine. UndecidableInstances
isn't all that scary; all it means is that the compiler could, instead of finding an instance, go into an infinite loop. That sounds pretty bad, until you realise that GHC actually has a limit to the number of steps it'll take to find an instance; nothing will go wrong unless you write a bad instance, and the error messages you get will generally make it very obvious what's gone wrong.1 Certainly it's a lot less scary than things like OverlappingInstances
(or worse, IncoherentInstances
).
The reason it complains is because MonadError
has a functional dependency from m
to e
. That means that the choice of m
determines what e
must be; i.e. every m
is associated with only one e
. The check for this (the Coverage Condition) is conservative, so it's easy to run into problems like this, where you try and "recurse down a level" to specify e
.
1 It'll list all the instances it looked at to try and find the one it's looking for, so you'll see a bunch of repeating lines. But usually you won't even run into trouble like this in the first place.
来源:https://stackoverflow.com/questions/9951382/making-a-custom-monad-transformer-an-instance-of-monaderror