2011-11-30 10 views
18

私が取り組んでいるライブラリでうまく構成する必要がある関数のセットのエラーを報告する最良の方法に苦労しています。 fooは一方向のみ(Maybeのために良いフィット)で失敗することができますが、barbazは、2つの異なる方法で各(良いフィットを失敗する可能性があります表現可能で構成可能なエラータイプ

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

具体的には、私は次のようになり機能を持っていますEither BarErrorsおよびEither BazErrors)。

一つの解決策は、作成することです:

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

と表現を犠牲にして、これらの機能の構成シーケンスによって発生する可能性があるエラーの範囲を表現している、すべての機能がEither AllTheErrorsを返す作りますそれぞれ個の可能なエラーの範囲機能。

両方の方法がありますか?多分モナドの構成以外の何かと?またはタイプの家族(波の手)...?

答えて

16

ライブラリ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を参照してください。

+0

賢い、ありがとう! – jberryman

+0

いくつかの研究をした後、私のライブラリに合っていると思うのは、ライブラリの関数を 'Failure'クラスの' failure 'パッケージ(http://hackage.haskell.org/package/failure)から多態的に定義することです。これは、タイプsigで発生することができる種類の例外を表現することができ、ユーザーには、「Maybe」のような単純なものや、制御モナド例外(インスタンスを提供する)のようなより堅牢なものを使用するオプションを与えます。再度、感謝します。 – jberryman

関連する問題