我正在尝试理解如何应用来自Haskel的Maybe-idiom ..我正在阅读http://en.wikibooks.org/wiki/Haskell/Understanding_monads/Maybe,这表明字典中的查找可能返回Maybe
并且此值支持通过>>=
运营商。
网址中的示例:
如果我们想在第三次查询中使用政府数据库查询的结果(比如我们想查看他们的注册号以查看他们是否欠任何汽车税),那么我们可以扩展我们的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”,而应报告哪个资源存在问题。
答案 0 :(得分:8)
你可以使用Either String
的monad实例,它基本上被定义为
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)
其中phonebook
,governmentalDatabase
和taxDatabase
与之前定义的一样,我们可以使用替代monadic查找函数,在Either String
中返回其结果 - 单子:
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"
答案 1 :(得分:5)
Maybe数据类型只有值“Nothing”用于表示错误。如果要返回特定的错误消息,我建议使用数据类型“Either”,它可以返回“Left a”或“Right a”值。详细了解如何在http://learnyouahaskell.com/for-a-few-monads-more#error
中使用该功能