if您可以直接以Ingo精美封装,或等效地执行此操作
breakOut :: a -> m (Either MyErrorType MyGoodResultType)
breakOut x = do
y <- dosomethingWith x
z <- doSomethingElseWith x y
if isNoGood z then return (Left (someerror z)) else do
w <- process z
v <- munge x y z
u <- fiddleWith w v
return (Right (greatResultsFrom u z))
Run Code Online (Sandbox Code Playgroud)
这对于根据您拥有的价值而做一些不同的事情是有好处的.
正如Michael Litchard正确指出的那样,你可以使用Control.Exception.它有大量的错误处理,控制流改变内容,如果你想做一些复杂的事情,值得一读.
如果您的错误产生可能发生在任何地方并且您的代码很复杂,那么这很好 您可以在顶级或您喜欢的任何级别处理错误.它非常灵活,不会弄乱您的退货类型.它只适用于IO monad.
import Control.Exception
Run Code Online (Sandbox Code Playgroud)
真的我应该滚动我自己的自定义类型,但我不能打扰派生类型等,所以我会用标准error函数和一些字符串来破解它.我对此感到非常内疚.
handleError :: ErrorCall -> IO Int
handleError (ErrorCall msg) = case msg of
"TooBig" -> putStrLn "Error: argument was too big" >> return 10000
"TooSmall" -> putStrLn "Error: argument was too big" >> return 1
"Negative" -> putStrLn "Error: argument was too big" >> return (-1)
"Weird" -> putStrLn "Error: erm, dunno what happened there, sorry." >> return 0
Run Code Online (Sandbox Code Playgroud)
错误处理程序需要使用显式类型catch.我已经把flip这个论点放在do了最后.
exceptOut :: IO Int
exceptOut = flip catch handleError $ do
x <- readLn
if (x < 5) then error "TooSmall" else return ()
y <- readLn
return (50 + x + y)
Run Code Online (Sandbox Code Playgroud)
这些设计适用于任何monad,而不仅仅是IO.它们与IO的例外具有相同的好处,因此官方的很好,但你需要了解monad变换器.如果您的monad不是IO,请使用它们,并且您有像我所说的Control.Exception一样的复杂要求.
首先,请阅读Gabriel Conzalez的"从一个循环中断开",EitherT根据出现的某些情况使用两种不同的东西,或者MaybeT在发生问题时直接停在那里.
如果你对Monad变形金刚一无所知,你可以从MartinGrabmüller的Monad变形金刚一步一步开始.它涵盖了ErrorT.之后再次阅读Breaking from a Loop!
您可能还想阅读Real World Haskell第19章"错误处理".
Continuation Passing Style callCC非常强大,但可能过于强大,当然也不会产生非常容易理解的代码.看到这个是一个相当积极的看法,这是非常消极的.