我有一个非常典型的设置,IO monad中有一组可以抛出错误的函数。到目前为止,我刚刚通过模式匹配runErrorT的结果来处理monad链末尾的错误:
replLisp :: LispScope -> String -> IO String
replLisp s input = do
result <- runErrorT (evalLisp s input)
return $ either (id) (show) result
我现在想为我的Hacked小方案添加一些错误处理,但是我很难让类型检查器开心。
如何使用catchError?一两个例子会有所帮助。
这是我最近的尝试:
catch :: [LispVal] -> IOThrowsError LispVal
catch [action rescue] = do
eval action >>= catchError $ eval rescue
答案 0 :(得分:7)
以下是使用catchError
从之前调用throwError
恢复的示例:
import Control.Monad.Error
import Control.Monad.Identity
type MyMonad = ErrorT String Identity
runMyMonad = runIdentity . runErrorT
main = do
let x = runMyMonad (func 5 0)
print x
func :: Double -> Double -> MyMonad Double
func w x = do
y <- (divider x) `catchError` (\_ -> return 1)
return (w + y)
divider :: Double -> MyMonad Double
divider x = do
when (x == 0) (throwError "Can not divide by zero!")
return (10 / x)
尽管我已经通过0
进行除法,但我们可以使用1
的处理程序结果来获取Right 6.0
的输出。
这有帮助吗?你的问题并没有真正说出问题所在。
答案 1 :(得分:0)
像Either和Maybe这样的错误monad不允许你在同一个monad中观察错误:你必须运行monad才能观察它。 IO中的异常是一个值得注意的例外(咳咳),因为IO是行的结尾......你不能再去那里了。
您有几种可能性:
由于您正在编写一个迷你解释器,因此明确管理所有异常可能是一个好主意,使用ErrorT monad仅用于 true ,不可恢复的错误。
对于您希望能够从中恢复的任何错误的调用,执行runErrorT并检查该结果,然后在当前monad中传递结果。