【问题标题】:Expressive and composable error types富有表现力和可组合的错误类型
【发布时间】:2012-01-09 09:19:28
【问题描述】:

我正在努力寻找最好的方法来报告一组应该很好地组合的函数中的错误,在我正在处理的库中。

具体来说,我的函数如下所示:

foo, bar, baz :: a -> Maybe a

其中foo 只能以一种方式失败(非常适合Maybe),但barbaz 可能以两种不同的方式失败(非常适合Either BarErrorsEither BazErrors) .

一种解决方案是创建:

data AllTheErrors = TheFooError
                  | BarOutOfBeer
                  | BarBurnedDown
                  | ...

并让所有函数返回Either AllTheErrors,它表达了这些函数的组合序列可能引发的错误范围,代价是表达每个个别功能。

有什么方法可以同时获得吗?也许除了一元组合之外的东西?还是与类型族(挥手)...?

【问题讨论】:

    标签: haskell error-handling composition


    【解决方案1】:

    Control.Monad.Exception 库允许在非 IO 代码中使用强类型异常。这允许函数抛出错误,并轻松地与抛出不同错误的函数组合。例如:

    {-# LANGUAGE RankNTypes, MultiParamTypeClasses, FunctionalDependencies #-}
    {-# LANGUAGE FlexibleInstances #-}
    import Prelude hiding (catch)
    import Control.Monad.Exception
    
    
    data FooException = FooException deriving (Show, Typeable)
    instance Exception FooException
    
    data BarErrors = BarErrors deriving (Show, Typeable)
    instance Exception BarErrors
    
    data BazErrors = BazErrors deriving (Show, Typeable)
    instance Exception BazErrors
    
    -- sample functions    
    foo :: (Throws FooException l) => a -> EM l a
    foo a = return a
    
    
    bar :: (Throws BarErrors l) => a -> EM l a
    bar _ = throw BarErrors
    
    baz :: (Throws BazErrors l) => a -> EM l a
    baz a = return a
    
    
    -- using all at once:
    
    allAtOnce :: (Throws FooException l, Throws BarErrors l, Throws BazErrors l) =>
                 a -> EM l String
    allAtOnce x = do
      _ <- foo x
      _ <- bar x
      _ <- baz x
      return "success!"
    
    -- now running the code, catching the exceptions:
    
    run :: a -> String
    run x = runEM $ allAtOnce x `catch` (\(_ :: FooException) -> return "foo failed")
            `catch` (\BarErrors -> return "bar failed")
            `catch` (\BazErrors -> return "baz failed")
    
    
    -- run 3 results in "bar failed"
    

    有关使用此库的更多详细信息,另请参阅论文 Explicitly Typed Exceptions for HaskellAn Extensible Dynamically-Typed Hierarchy of Exceptions

    【讨论】:

    • 在做了一些研究之后,我认为适合我的库的方法是在'failure'包的Failure类中多态地定义我的库的函数,这里:hackage.haskell.org/package/failure。这让我可以表达可以在类型 sig 中引发的异常类型,并让我的用户可以选择使用像 Maybe 这样简单的东西,或者像 control-monad-exception(它提供一个实例)这样更健壮的东西。再次感谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-18
    • 1970-01-01
    • 2012-01-10
    • 1970-01-01
    • 2021-04-02
    • 2012-05-07
    相关资源
    最近更新 更多