【问题标题】:Haskell monads and a fail that doesn't require a stringHaskell monads 和一个不需要字符串的失败
【发布时间】:2011-12-22 21:41:36
【问题描述】:

我有以下 monad 转换器来处理 Haskell 中的错误。

instance (Monad m, Error e) => Monad (EitherT e m) where
    return = EitherT . return . return
    m >>= k  = EitherT $ do
            a <- runEitherT m
            case a of
                Left  l -> return (Left l)
                Right r -> runEitherT (k r)
    fail = EitherT . return . Left . strMsg

它工作得很好,因为我可以使用自定义类来实例化Error,并且有一种非常灵活的方式来处理错误。

fail 有点傻,因为它是String -&gt; EitherT e m 类型,而String 限制可能是一种令人讨厌的创建错误的方式。我最终得到了很多:

instance Error BazError where
    strMsg "foo" = FooError -- oh look we have no error context
    strMsg "bar" = BarError -- isn't that nice

我想做的是创建一个新函数,比如fail,它的类型是a -&gt; e,这样我就可以删除(Error e) 限制。 fail 在 monad 堆栈变大时特别方便,比如当我结束时

EitherT BazError (StateT [BazWarning] IO) Foo

有没有一种方法可以创建一个与fail 行为相同但类型限制较少的函数?还是fail 是用深层次的haskell 暗魔法实现的?

【问题讨论】:

  • 你应该完全避免fail,除非你想自定义失败的do-block模式匹配的行为。

标签: haskell monads monad-transformers


【解决方案1】:

好吧,fail 会在 do 块中出现模式匹配失败时被调用,例如 Just x &lt;- somethingsomething 的结果是 Nothing。除此之外,fail 是一个普通函数。

对于strMsg "foo" = FooError 等问题,throwError 是否为您的用例提供了更好的界面?

【讨论】:

    【解决方案2】:

    这篇文章可能有用:http://blog.ezyang.com/2011/08/8-ways-to-report-errors-in-haskell-revisited/

    您的 EitherT 已经在标准库中并称为 ErrorT。查看文档:http://hackage.haskell.org/packages/archive/mtl/latest/doc/html/Control-Monad-Error.html#t:ErrorT

    fail 现在是历史奇闻,可能被认为是设计缺陷,同时缺少Functor a =&gt; Monad a 约束。在 do 表示法中处理失败的模式匹配只是一个有争议的功能。

    throwError :: MonadError e m => e -> m a
    

    fail 的最常见替代品,但还有更多可用的替代品(参见文章)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-12-07
      • 1970-01-01
      • 2011-02-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多