打破monad序列

r.s*_*cky 4 haskell

是否有可能打破monad序列?

例如,如果我想根据在序列中间计算的某些条件先断开序列.比如,在'do'表示法中,我绑定一个值,并根据我想要完成序列或停止它的值.有没有像'通行证'这样的功能?

谢谢.

And*_*ewC 9

直接使用 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)

这对于根据您拥有的价值而做一些不同的事情是有好处的.

在IO monad中使用异常

正如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变形金刚等

这些设计适用于任何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章"错误处理".

呼叫/ CC

Continuation Passing Style callCC非常强大,但可能过于强大,当然也不会产生非常容易理解的代码.看到这个是一个相当积极的看法,是非常消极的.

  • 如果使用EitherT monad变压器,可以使该代码更清洁 - 尤其是返回部件.在这里和那里提供一些电梯的(潜在)成本. (3认同)