1

我试图了解如何应用 Haskel 的 Maybe-idiom。我正在阅读http://en.wikibooks.org/wiki/Haskell/Understanding_monads/Maybe这表明字典中的查找可能会返回一个Maybe和该值通过>>=运算符传播。

来自 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-block 样式:

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

问题:

我如何处理错误处理?我认为大多数代码将受益于告诉哪里出了问题。而不是仅仅报告“在电话簿或政府数据库中找不到 John Doe”,它应该报告哪个资源有问题。

4

2 回答 2

8

您可以使用 monad 实例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)

where phonebook, governmentalDatabase, andtaxDatabase是你之前定义的,我们可以使用一个替代的 monadic 查找函数,它在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

说明 monad 的强大功能,现在唯一需要在客户端函数中更改的是类型签名:

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"
于 2012-08-13T10:47:19.543 回答
5

Maybe 数据类型只有值“Nothing”来表示错误。如果您想返回特定的错误消息,我建议使用数据类型“Either”,它可以返回“Left a”或“Right a”值。在http://learnyouahaskell.com/for-a-few-monads-more#error阅读更多关于如何使用它的信息

于 2012-08-13T09:24:43.963 回答