shooqie
shooqie

Reputation: 1022

throwE and catchE with ExceptT monad on the bottom of monadic stack

Say I have a monadic stack like this:

import Control.Monad.Trans.Reader
import Control.Monad.Trans.Except
import Control.Monad.Trans

type MyMonad = ReaderT Env (ExceptT String IO) -- Env is irrelevant

And a function (simplified, but the idea holds):

f :: Integer -> MyMonad Integer
f 42 = lift $ throwE "42 is an ILLEGAL number"
f n = return n

What I now want to do is call f from another function, but catch the thrown exception if it occurs and somehow handle it (for instance, throw another exception but with the message changed). I'm having a hard time figuring out what kind of lift operations should be done here for it to be done properly. I tried something like this:

g n = do
  x <- (f n) `catchE'` (\_ -> lift $ throwE "nope, still illegal")
  return x
where catchE' - lift . catchE

but it obviously won't work because catchE' takes something in the ExceptT monad, not MyMonad. Can it be done easily? Perhaps changing the structure of the monad stack could help?

Upvotes: 3

Views: 270

Answers (1)

Li-yao Xia
Li-yao Xia

Reputation: 33399

You need more than lift to lift catch through a monad transformer. In fact, there are transformers with no way to lift catch at all (such as ContT). However for ReaderT there is, and the easiest way to make use of that is via Control.Monad.Error.catchError from the mtl library.

Upvotes: 5

Related Questions