我有一个非常典型的设置,在IO单子中有一组函数可以抛出错误。到目前为止,我只是通过模式匹配runerror:
的Either结果来处理monad链末尾的错误。replLisp :: LispScope -> String -> IO String
replLisp s input = do
result <- runErrorT (evalLisp s input)
return $ either (id) (show) result
我现在想添加一些错误处理到我的黑客小方案,但我有麻烦,使类型检查器高兴。
如何使用catchError?举一两个例子会有帮助的。
这是我最近的一次尝试:
catch :: [LispVal] -> IOThrowsError LispVal
catch [action rescue] = do
eval action >>= catchError $ eval rescue
下面是使用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
的输出。
这有帮助吗?你的问题并没有真正说明问题所在
像Either和Maybe这样的错误单子不允许你在同一个单子内观察错误:你必须运行单子才能观察它。IO中的异常是一个值得注意的例外(嗯哼),因为IO是一行的结尾……你不能再往前走了。
你有几种可能性:
-
由于您正在编写一个迷你解释器,因此显式管理所有异常可能是一个好主意,仅对true,不可恢复的错误使用errt单子。
-
对于任何可能出错的调用,您希望能够从中恢复,在将结果传递到当前monad之前,执行runerror并检查结果。