在我正在工作的库中,我正在努力寻找一种最好的方法来报告一组函数中的错误,这些函数应该组合得很好。
具体地说,我的函数如下所示:
foo, bar, baz :: a -> Maybe a
其中foo
可能只以一种方式失败(非常适合Maybe
),但是bar
和baz
可能会以两种不同的方式失败(非常适合Either BarErrors
和Either BazErrors
)。
一种解决方案是创建:
data AllTheErrors = TheFooError
| BarOutOfBeer
| BarBurnedDown
| ...
并使所有函数返回Either AllTheErrors
,它表示由这些函数组成的序列可能引发的错误范围,但代价是表示每个单独函数可能出现的错误范围。
有没有办法让我两者兼得?也许可以使用一元组合之外的其他东西?或者使用类型族(波形手)...?
发布于 2011-11-30 12:34:15
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 Haskell和An Extensible Dynamically-Typed Hierarchy of Exceptions。
https://stackoverflow.com/questions/8320855
复制相似问题