使错误适应 Except

Adapting Error to Except

现在 Control.Monad.Error 已被弃用,Control.Monad.Except 占据主导地位,很多在线资源都没有跟上,仍然展示了如何使用 Error 的示例。

那我要怎么转

instance Error MyError where
  noMsg  = ...
  strMsg = ...

使用 Except 转换成某种东西。只是将 Error 替换为 Except 并没有起作用,因为 Except 需要额外的类型参数

我知道 Except 中不存在那些确切的方法,那么有什么替代方法?

简短的回答是:将 Error 完全替换为任何内容,将 ErrorT 替换为 ExceptT,只要您不使用 [=16],事情就会继续进行=]s 方法,fail(现在有不同的定义),或在 do 表示法中失败的模式匹配。

Control.Monad.Error系统与新Control.Monad.Except系统的本质区别是新系统对没有class限制error/exception 类型。

我们发现,以多态方式使用任何 error/exception 类型的能力比自定义字符串错误消息转换的有点老套的能力更有用。

所以 class Error 就这样消失了。

作为副作用,ExceptTfail 现在已从底层 monad 中移除。这也改变了 do 表示法中失败模式的影响。

旧的定义是:

fail msg = ErrorT $ return (Left (strMsg msg))

我认为相当于

fail msg = throwError (strMsg msg)

如果您仍然需要这种行为,您可以改用

throwError yourIntendedErrorValue

(如果您使用 transformers(即 Control.Monad.Trans.Except)而不是 mtl,则 throwE 会起作用。)

旧的 do 模式匹配失败将适用于

do
    Just x <- myErrorTAction
    ...

实际操作时returnsNothing。这更尴尬,但你可以,例如将其替换为明确的 case 匹配项(本质上是对其进行脱糖):

do
    y <- myErrorTAction
    case y of
        Nothing -> throwE ...
        Just x -> do
           ...

@DanielWagner 建议采用以下方法避免额外缩进:

do
    x <- myErrorTAction >>= maybe (throwError ...) return
    ...

Error 的删除也消除了 Control.Monad.Error 的命名不一致的需要:大多数转换器遵循 SomethingT 是转换器名称的规则,并且 SomethingSomethingT ... Identity 的类型别名。旧的 ErrorT 打破了这一点,因为 Error class 用于完全不同的东西。

在新系统中,Except e = ExceptT e Identity,与其他变形金刚一样。