First, the code
newtype Exceptional e m a = Exceptional { deExceptional :: m a }
deriving (Functor, Applicative, Monad)
instance (Exception e, MonadThrow m) => MonadError e (Exceptional e m) where
throwError = Exceptional . throwM
catchError m f = do
a <- try (deExceptional m)
case a of
Left e -> f e
Right a -> return a
runExceptional :: (Exception e, MonadCatch m) => Exceptional e m a -> m (Either e a)
runExceptional = try . deExceptionalThe above is basically ExceptT, though we don't incur another layer in the monad stack. This isn't particularly interesting (though might bring performance gains). The real use is that Exceptional can have a valid MonadMask instance. This means we can actually bracket in this monad transformer, which isn't possible with ExceptT (at least, not with MonadMask from exceptions).