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(它提供了一个实例)。再次感谢。