2011-11-30 32 views
18

我正努力用最好的方式報告一組函數中的錯誤,這些函數應該在我正在編寫的庫中很好地編寫。表達式和可組合的錯誤類型

具體而言,我有一個看起來像功能:

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

其中foo只能以一種方式(非常適合Maybe)失敗,但barbaz可以在每個兩種不同的方式失敗(良好擬合對於Either BarErrorsEither 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'這樣簡單的東西的選項,或者像control-monad-exception(它提供了一個實例)那樣更強大的選項。再次感謝。 – jberryman