说我有一个像这样的单子堆栈:
import Control.Monad.Trans.Reader
import Control.Monad.Trans.Except
import Control.Monad.Trans
type MyMonad = ReaderT Env (ExceptT String IO) -- Env is irrelevant
还有一个函数(简化了,但是这个想法成立了):
f :: Integer -> MyMonad Integer
f 42 = lift $ throwE "42 is an ILLEGAL number"
f n = return n
我现在想做的是从另一个函数调用f
,但是如果发生了抛出的异常并以某种方式对其进行了处理(例如,抛出另一个异常,但是消息已更改)。我很难确定在这里应该执行哪种举升操作才能正确完成。我尝试过这样的事情:
g n = do
x <- (f n) `catchE'` (\_ -> lift $ throwE "nope, still illegal")
return x
where catchE' - lift . catchE
,但是显然不起作用,因为catchE'
用ExceptT
单子而不是MyMonad
取某物。能容易做到吗?也许更改monad堆栈的结构可能会有所帮助?
答案 0 :(得分:3)
您需要超过lift
才能通过单声道变压器提升catch
。实际上,有些变压器根本无法举起catch
(例如ContT
)。但是对于ReaderT
来说,存在,最简单的使用方法是通过mtl库中的Control.Monad.Error.catchError
。