Skip to content

Instantly share code, notes, and snippets.

@ocharles
Last active May 13, 2018 22:27
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ocharles/cab1397182c1c76b40f20c884fc5ca93 to your computer and use it in GitHub Desktop.
Save ocharles/cab1397182c1c76b40f20c884fc5ca93 to your computer and use it in GitHub Desktop.

MonadError via MonadCatch and MonadThrow

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

So why not ExceptT?

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

Does this exist anywhere already?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment