Haskell 表达性和可组合性错误类型

Haskell 表达性和可组合性错误类型,haskell,error-handling,composition,Haskell,Error Handling,Composition,在我正在开发的库中,我正在努力寻找报告一组函数中的错误的最佳方法,这些函数应该组合得很好 具体来说,我的函数如下所示: foo, bar, baz :: a -> Maybe a 其中,foo只能以一种方式失败(很适合可能),但是bar和baz可以分别以两种不同的方式失败(适合任何一种错误和任何一种错误) 一种解决方案是创建: data AllTheErrors = TheFooError | BarOutOfBeer

在我正在开发的库中,我正在努力寻找报告一组函数中的错误的最佳方法,这些函数应该组合得很好

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

foo, bar, baz :: a -> Maybe a
其中,
foo
只能以一种方式失败(很适合
可能
),但是
bar
baz
可以分别以两种不同的方式失败(适合
任何一种错误
任何一种错误

一种解决方案是创建:

data AllTheErrors = TheFooError
                  | BarOutOfBeer
                  | BarBurnedDown
                  | ...
并使所有函数返回
或AllTheErrors
,它表示这些函数的组合序列可能引起的错误范围,但代价是表示每个函数可能出现的错误范围

有什么办法我可以两者兼得吗?也许是用一元合成以外的东西?或者使用类型族(waves hands).?

库允许在非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"
{-#语言等级,多段类型类,函数依赖性#-}
{-#语言灵活实例}
导入前奏隐藏(catch)
导入控制.Monad.Exception
数据FooException=FooException派生(显示,可键入)
实例异常FooException
数据错误=错误派生(显示,可键入)
实例异常错误
数据错误=衍生错误(显示,可键入)
实例异常错误
--样本函数
foo::(抛出FooException l)=>a->EM l a
foo a=返回a
条::(抛出错误l)=>a->EM l a
bar=抛出错误
baz::(l)=>a->EM l a
baz a=返回a
--一次使用全部:
allAtOnce::(抛出FooException l,抛出BarErrors l,抛出BazErrors l)=>
a->EM l字符串
阿拉通斯x=do
_返回“bar失败”)
`捕获“%baz错误->返回“baz失败”)
--在“bar失败”中运行3个结果

有关使用此库的更多详细信息,请参见论文和。

在做了一些研究之后,我认为适合我的库的是在“Failure”包的
Failure
类中以多态方式定义我的库的函数,如下所示:。这让我能够表达在类型sig中可以引发的异常类型,并让我的用户可以选择使用一些简单的东西,比如
也许
,或者一些更健壮的东西,比如control monad exception(它提供了一个实例)。再次感谢。