Reputation: 3260
I'm going back through Monad Transformers : Step by Step as a refresher, and like many tutorials out there, it uses Control.Monad.Error
. GHC now gives a warning that this module is deprecated, so I switched over to Control.Monad.Trans.Either
from the either
library: http://hackage.haskell.org/package/either-3.4/docs/Control-Monad-Trans-Either.html
Everything is handled smoothly with eval2
in the paper, since EitherT
is the outermost monad. However, after that everything falls apart -- ReaderT
is in no way an Either
value, and everything henceforth uses ErrorT
, which I'd like to change to EitherT
.
My idea, then, was to define a MonadEither
type class that boxed left
and right
in order to handle errors, but this hasn't been fruitful. I don't really understand how the type classes in mtl
work, and this instance in particular has to be parameterized over multiple values, which is confusing. I came up with the following, which compiles after including some syntactic extensions:
class (Monad m) => MonadEither l r m | m -> r where
right :: r -> m r
left :: l -> m r
But I can't figure out a MonadEither
instance of EitherT
:
instance Monad m => MonadEither l r (E.EitherT l m) where
right = E.right
left = E.left
Edit: I changed the instance declaration to match E.EitherT
properly, and get the following error message:
Illegal instance declaration for ‘MonadEither l r (E.EitherT l m)’
The coverage condition fails in class ‘MonadEither’
for functional dependency: ‘m -> r’
Reason: lhs type ‘E.EitherT l m’ does not determine rhs type ‘r’
In the instance declaration for ‘MonadEither l r (E.EitherT l m)’
Again, I'm not really sure what I'm doing. I don't really understand functional dependencies, so I'm just looking for some guidance as to what an appropriate MonadEither
type class might look like, if possible to define.
Upvotes: 4
Views: 203
Reputation: 9414
How about
instance Monad m => MonadEither l r (E.EitherT l m)
That is, it should be l
instead of r
.
However once you've done this you'll come up across a separate error. The root cause is that there's no point to right
; it's just return
. This means you need to get rid of the r
parameter to the class.
class Monad m => MonadEither l m where
left :: l -> m a
Your instance declaration should then become
instance Monad m => MonadEither l (E.EitherT l m)
(You also may want to look at the MonadError
class since this is essentially what you are replicating.)
Upvotes: 4