打破单子序列 [英] Breaking out of monad sequence

查看:82
本文介绍了打破单子序列的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否有可能突破monad序列?

例如,如果我想根据中间计算的某些条件提前突破序列的序列。比如说,在'do'符号中,我绑定一个值并根据我想要的值完成序列或停止它。有没有像'传递'函数?



谢谢。

解决方案

< h2>直接使用 if

您可以直接使用 Ingo精美封装,或者等价地例如

  breakOut :: a  - > m(MyErrorType MyGoodResultType)
breakOut x = do
y< - dosomethingWith x
z< - doSomethingElseWith xy
if isNoGood z then return(Left(someerror z))else do
w< - 进程z
v< - munge xyz
u< - fiddleWith wv
return(Right(greatResultsFrom uz))



这对于简单地根据您拥有的值来做不同的事情是很好的。



使用异常在IO monad中



您可以使用 Control.Exception Michael Litchard正确指出了。它有大量的错误处理,控制流改变它的东西,值得一读,如果你想做一些复杂的。



这很好,如果你的错误产生可能发生在任何地方,而且你的代码很复杂您可以在最高级别或任何级别处理错误。它非常灵活,不会混淆你的返回类型。它只适用于IO单元。

  import Control.Exception 

真的我应该推出我自己的自定义类型,但是我不能为派生Typable等而烦恼,所以我会用标准的错误函数和一些字符串。我感到非常内疚。

  handleError :: ErrorCall  - > IO Int 
handleError(ErrorCall msg)= case msg
TooBig - > putStrLn错误:参数太大>>返回10000
TooSmall - > putStrLn错误:参数太大>>返回1
否定 - > putStrLn错误:参数太大>>返回(-1)
奇怪 - > putStrLn错误:呃,不知道那里发生了什么,抱歉。 >>返回0

错误处理程序需要显式类型用于 catch 。 $ 翻转使参数 do 成为最后一个。


$ (x <5)b $ b

  exceptOut :: IO Int 
exceptOut = flip catch handleError $ do
x< - readLn
然后错误TooSmallelse return()
y< - readLn
return(50 + x + y)



Monad变压器等



这些设计用于处理任何monad,而不仅仅是IO。他们与IO的例外有相同的好处,所以官方很棒,但你需要了解monad变形金刚。如果你的monad不是IO,那么使用它们,并且你有复杂的需求,比如我说的Control.Exception。

首先,阅读 Gabriel Conzalez从循环中分手使用 EitherT 根据出现的一些情况做两件事情,或者 MaybeT ,以便在发生问题时立即停止。



如果你对Monad Transformers一无所知,你可以从开始一步一步马丁Grabmüller的Monad变压器。它涵盖 ErrorT 。之后,再次阅读从循环中断!



您可能还想阅读真实世界Haskell第19章,错误处理


$ b

Call / CC



持续传递样式的 callCC 非常强大,但也许功能太强大了,当然也不会产生非常易于理解的代码。请参阅以获得相当积极的回应,并且这个为非常消极的一个。


Is it possible to break out of a monad sequence?

For instance, if I want to break out of a sequence earlier based on some condition calculated in the middle of the sequence. Say, in a 'do' notation I bind a value and based on the value I want to either finish the sequence or stop it. Is there something like a 'pass' function?

Thanks.

解决方案

Directly using if

You could do this directly as Ingo beautifully encapsulated, or equivalently for example

    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))

This is good for simply doing something different based on what values you have.

Using Exceptions in the IO monad

You could use Control.Exception as Michael Litchard correctly pointed out. It has tons of error-handling, control-flow altering stuff in it, and is worth reading if you want to do something complex with this.

This is great if your error production could happen anywhere and your code is complex. You can handle the errors at the top level, or at any level you like. It's very flexible and doesn't mess with your return types. It only works in the IO monad.

import Control.Exception

Really I should roll my own custom type, but I can't be bothered deriving Typable etc, so I'll hack it with the standard error function and a few strings. I feel quite guilty about that.

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

The error handler needs an explicit type to be used in catch. I've flipped the argument to make the do block come last.

exceptOut :: IO Int
exceptOut = flip catch handleError $ do
     x <- readLn
     if (x < 5) then error "TooSmall" else return ()
     y <- readLn
     return (50 + x + y)

Monad transformers etc

These are designed to work with any monad, not just IO. They have the same benefits as IO's exceptions, so are officially great, but you need to learn about monad tranformers. Use them if your monad is not IO, and you have complex requirements like I said for Control.Exception.

First, read Gabriel Conzalez's Breaking from a loop for using EitherT to do two different things depending on some condition arising, or MaybeT for just stopping right there in the event of a problem.

If you don't know anything about Monad Transformers, you can start with Martin Grabmüller's Monad Transformers Step by Step. It covers ErrorT. After that read Breaking from a Loop again!

You might also want to read Real World Haskell chapter 19, Error handling.

Call/CC

Continuation Passing Style's callCC is remarkably powerful, but perhaps too powerful, and certainly doesn't produce terribly easy-to-follow code. See this for a fairly positive take, and this for a very negative one.

这篇关于打破单子序列的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆