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 . deExceptional
The 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
).