可表达和可组合的错误类型 [英] Expressive and composable error types

查看:62
本文介绍了可表达和可组合的错误类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我正在研究的库中,最好的方法是报告一组应该很好组合的函数中的错误,我一直在努力.

I am struggling with the best way to report errors in a set of functions that should compose nicely, in a library I'm working on.

具体来说,我具有如下功能:

Concretely, I have functions that look like:

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

其中 foo 只能以一种方式失败(非常适合 Maybe ),但是 bar baz 可能会以两种不同的方式失败(非常适合 Ether BarErrors Ether BazErrors ).

where foo can fail in only one way (a good fit for Maybe), but bar and baz can fail in two different ways each (good fits for Either BarErrors and Either BazErrors).

一种解决方案是创建:

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

并使所有函数返回 AllTheErrors ,它表示这些函数的组成序列可能引起的错误范围,但以表示范围为代价每个单个函数可能出现的错误.

and make all the functions return Either AllTheErrors, which expresses the range of errors that might be raised by a composed sequence of these functions at the expense of expressing the range of errors possible for each individual function.

有没有办法我能兼得?也许除了莫纳德成分之外还有其他东西吗?还是带有类型家族(挥手)...?

Is there a way I can get both? Maybe with something other than monadic composition? Or with type families (waves hands)...?

推荐答案

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

The Control.Monad.Exception library allows strongly typed exceptions to be used in non IO code. This allows functions to throw errors, and easily compose with functions that throw different errors. For example:

{-# 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"

另请参见论文 Haskell的明确类型异常

See also the papers Explicitly Typed Exceptions for Haskell and An Extensible Dynamically-Typed Hierarchy of Exceptions for more details on using this library.

这篇关于可表达和可组合的错误类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆