MonadPlus IO不是一个简单的东西 [英] MonadPlus IO isn't a monoid

查看:49
本文介绍了MonadPlus IO不是一个简单的东西的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

实例 MonadPlus IO 是唯一的,因为 mzero 抛出:

Instance MonadPlus IO is unique because mzero throws:

Prelude Control.Monad> mzero
*** Exception: user error (mzero)

因此, MonadPlus IO 暗示它也旨在解决错误.

So accordingly, MonadPlus IO implies that it is also intended for errors.

mzero 显然可以用作标识元素:

mzero apparently serves as the identity element if the other action doesn't throw:

Prelude Control.Monad> mzero `mplus` return 0
0
Prelude Control.Monad> return 0 `mplus` mzero
0

但是当两个动作都抛出时却没有:

But it doesn't when both actions throw:

Prelude Control.Monad> fail "Hello, world!" `mplus` mzero
*** Exception: user error (mzero)
Prelude Control.Monad> mzero `mplus` fail "Hello, world!"
*** Exception: user error (Hello, world!)

所以 MonadPlus IO 并不是一个monoid.

So MonadPlus IO is not a monoid.

如果用户意图出错时它违反了 MonadPlus 法律,那么它的真正目的是什么?

If it violates MonadPlus laws when user intends errors, what is it actually intended for?

推荐答案

IO 是相对于标识异常的等价类的类.没那么令人满意.一种替代方法可能如下所示:

IO under mplus is a monoid relative to an equivalence class that identifies exceptions. Not that satisfying. An alternative approach might look like this:

m <|> n = m `catches`
  [ Handler $ \ ~EmptyIO -> n
  , Handler $ \ ~se@(SomeException _) ->
      n `catch` \ ~EmptyIO -> throwIO se ]

此方法的主要问题是处理程序可以堆叠.当第一个动作失败时,我们不能仅仅执行第二个动作.一个较小的问题是,没有一种完全可靠的方法来确定异常是同步的(应该使用 throwIO 抛出)还是异步的(在这种情况下,我们需要使用 throwTo 和我们自己的线程ID).这样一团糟.

The main problem with this approach is that handlers can stack up. When the first action fails, we can't just commit to the second action. A smaller issue is that there's no completely reliable way to determine whether an exception is synchronous (and should be rethrown using throwIO) or asynchronous (in which case we need to rethrow it using throwTo with our own thread ID). So that way lies messes.

这篇关于MonadPlus IO不是一个简单的东西的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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