I have the following monad stack:
import Control.Monad.Trans.State ( runStateT, StateT )
import Control.Monad.Trans.Except ( catchE, throwE, runExcept, Except )
type MyMonad a = StateT Int (StateT Char (Except String)) a
runMyMonad :: MyMonad a -> Char -> Int -> Either Error ((a, Int), Char)
runMyMonad f c i = runExcept $ runStateT (runStateT f i) c
If I want to throw an error in an action, I can do this:
-- Takes an Int and returns its double.
-- Throws an error if it is not larger than 5.
myAction :: Int -> MyMonad Int
myAction a =
if a > 5
then return $ a*2
else lift . lift $ throwE "There was an error"
That works, but I can't catch that error in another action like this:
-- Returns 0.
myBaseAction :: MyMonad Int
myBaseAction = return 0
-- Takes an Int and returns its double.
-- Returns 0 if it is not larger than 5.
mySafeAction :: Int -> MyMonad Int
mySafeAction a = lift . lift $ catchE (myAction a) (\e -> myBaseAction)
Haskell complains about the types of the arguments of catchE, saying that it expected an ExceptT but I gave it a MyMonad. How can I make catchE take MyMonad? I've read about the liftCatch function in some posts, but I can't find it anywhere.