2013-09-30 29 views
1

我有不同的構造函數的自定義錯誤類型,姑且稱之爲MyError避免無意義的聲明例如錯誤

data MyError = ConditionA String | ConditionB String | ConditionC String 

的構造分類錯誤的類型,以及字符串提供更多細節。 我想用我的錯誤類型在Either單子,比如我要像

myFunction :: a -> Either MyError a 

內myFunction的功能,我想在MissingH使用maybeToEither功能從Data.Either.Utils

maybeToEither :: MonadError e m => e -> Maybe a -> m a 

但ghc告訴我要做到這一點,我必須製作MyErrorError的實例。這似乎回落到MonadError要求m是一個單子的事實,併爲Either e單子實例都需要,因爲failError e

instance (Error e) => Monad (Either e) where 
    return  = Right 
    Left l >>= _ = Left l 
    Right r >>= k = k r 
    fail msg  = Left (strMsg msg) 

我怎麼能避免一個無意義的Error實例聲明爲MyError

我注意到的Database.MongoDB.Query作者曾與他們Failure數據類型相同的問題(其中也有多個構造函數,因此,沒有合理的Error實例),以及他們的解決方案是治療使用fail爲錯誤:

instance Error Failure where strMsg = error 

這是我最好的選擇嗎?

+0

爲什麼這是一個荒謬的例子?您告訴GHC如何使用您的類型來存儲錯誤消息,這對我來說似乎很合理。 – jozefg

+0

因爲它有多個構造函數,所以你不能根據對strMsg的調用來選擇正確的構造函數 – mskel

回答

3

不要使用MissingH庫這一點。只需使用與每個版本的GHC編譯器捆綁在一起的基本庫。除非您的代碼明確要求使用MonadError類(從mtl庫)出於某些重要原因,否則可以避免使用該類,從而避免在錯誤類型上需要使用Error實例。

與基礎庫的4.3版本開始 - 2010年11月發佈的 - 的Either e標準Monad實例確實要求e是的Error一個實例。所以,你可以只包括線

import Control.Monad.Instances() 

在您的模塊的頂部,然後隨意使用類型Either MyError作爲Monad

使用此功能,而不是MissingH的maybeToEither

maybeToEither :: e -> Maybe a -> Either e a 
maybeToEither e = maybe (Left e) Right 

如果你真的需要爲EitherMonadError情況下,你就必須修改您的MyError型以某種方式人工提供Error實例。請參閱@ jozefg的答案,以獲得關於如何做到這一點的更詳細建議。即使那樣,我個人也不會爲了這樣簡單的事情而煩心地把整個MissingH庫拉進去。

+0

Yitz的答案很好。你可能也想看看'錯誤'包 – GarethR

1

你有3個選擇

  1. 的情況下加入MyError

    data MyError = FailCase String 
          | ... 
    

    很簡單,BU有點難看。

  2. 它傳遞給error

    這就是DD爲DB手柄,但運行時錯誤吸也許這應該是可以避免的。

  3. MyError換成Either(或Maybe或其他處理錯誤情況的東西)。

    type MyErrorMonad = Either (Either String MyError) 
    

    然後你只需要定義一些同義詞。這是更打字,但可能是最清潔的概念。它迫使你明確處理fail被調用的情況。

    caseA = Right . CaseA 
    .... 
    

    instance Error (Either String b) where strMsg = Left