Reputation: 1022
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
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