5

我有以下 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不过,这有点傻,因为它是 type String -> 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 -> e,以便我可以删除(Error e)限制。fail当 monad 堆栈变大时特别方便,比如当我结束时

EitherT BazError (StateT [BazWarning] IO) Foo

有没有办法创建一个fail与限制较少的类型具有相同行为的函数?或者是fail使用 deep haskell 暗魔法实现的?

4

2 回答 2

7

好吧,fail如果你在 do 块中出现模式匹配失败,就会调用它,比如你有Just x <- somethingandsomething的结果是Nothing. 除此之外,fail是一个普通的功能。

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

于 2011-12-22T10:08:09.880 回答
4

这篇文章可能有用: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 => Monad a约束。在do符号中处理失败的模式匹配只是一个有争议的特性。

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

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

于 2011-12-22T13:27:24.623 回答