2012-08-13 25 views
1

我想了解如何應用哈斯克爾的可能成語。我正在閱讀http://en.wikibooks.org/wiki/Haskell/Understanding_monads/Maybe,它顯示在字典中查找可能會返回Maybe,並且此值通過>>=運算符提出。Errorhandling和monads?

從URL的例子:

然後如果我們想在第三查找使用該結果從政府數據庫查詢(比如我們想看看他們的註冊號,看看他們是否欠任何汽車稅) ,那麼我們可以擴展我們的getRegistrationNumber功能:

getTaxOwed :: String  -- their name 
      -> Maybe Double -- the amount of tax they owe 
getTaxOwed name = 
    lookup name phonebook >>= 
    (\number -> lookup number governmentalDatabase) >>= 
     (\registration -> lookup registration taxDatabase) 

或者,使用DO塊風格:

getTaxOwed name = do 
    number  <- lookup name phonebook 
    registration <- lookup number governmentalDatabase 
    lookup registration taxDatabase 

問題:

如何處理錯誤處理?我認爲大多數代碼都會從告訴事情出錯的地方受益。不是僅僅報告「在電話簿或政府數據庫中找不到John Doe」,它應該報告哪個資源有問題。

+1

你發現的是,如果只有一個可能的失敗案例,那麼Maybe可能是最有用的,認爲負數的平方根。另一方面,你可以使'sqrt ::複合雙' – Sarah 2012-08-13 09:50:26

+0

是的,你是對的。這裏是問題的一般解決方案http://hackage.haskell.org/packages/archive/transformers/0.3.0.0/doc/html/Control-Monad-Trans-Error.html。也許不是關於準確的錯誤處理 – permeakra 2012-08-13 11:50:15

回答

8

您可以使用單子實例Either String,基本上是定義爲

instance Monad (Either String) where            
    fail msg = Left msg                
    return x = Right x                

    Left msg >>= k = Left msg              
    Right x >>= k = k x 

(實際的定義更復雜一些。)

如果我們然後將字典定義爲由標籤和查找表組成的對

type Dict a b = (String, [(a, b)]) 

phonebook' :: Dict String Int 
phonebook' = ("phone book", phonebook) 

governmentalDatabase' :: Dict Int Int 
governmentalDatabase' = ("governmental database", governmentalDatabase) 

taxDatabase' :: Dict Int Double 
taxDatabase' = ("tax database", taxDatabase) 

其中phonebookgovernmentalDatabasetaxDatabase是因爲你在他們面前的定義,我們可以使用其他的單子查找函數返回其結果在Either String -monad:

lookup' :: (Eq a, Show a) => a -> Dict a b -> Either String b 
lookup' key (descr, table) = case lookup key table of 
    Nothing -> Left ("couldn't find " ++ show key ++ " in " ++ descr) 
    Just val -> Right val 

龍虎鬥單子的勢力,唯一的事情,現在需要在您的客戶端功能改變的是類型簽名:

getTaxOwed :: String    -- their name         
      -> Either String Double -- either an error message      
            -- or the amount of tax they owe    
getTaxOwed name = do 
    number  <- lookup' name phonebook' 
    registration <- lookup' number governmentalDatabase' 
    lookup' registration taxDatabase' 

一個未知的名字運行這個功能可以使:

> getTaxOwed "Joe" 
Left "couldn't find \"Joe\" in phone book"