使用Maybe's从ADT链中检索值

时间:2013-01-25 19:13:12

标签: haskell maybe

我有一些ADT,每个ADT可能包含或不包含另一个ADT。我需要从较低级别检索数据,并且我正在编写一些非常重复的代码,我相信这些代码可以被删除。我已经看过Real World Haskell中的一些示例代码以及“了解大好的Haskell”,但我无法弄明白。这是一个例子,其中遗漏了ADT的无关细节。

  T24Report
      - projTitle :: Maybe ProjectTitle
            - zip :: Maybe String

要从街道地址检索邮政编码,我一直以此结束:

 projNameStr :: T24Report -> String
 projNameStr t24 = if isNothing projTitleMaybe
                    then ""
                    else (fromMaybe "") $ zip $ fromJust projTitleMaybe
                where
                    projTitleMaybe = projTitle $ project t24

随着对象链的深度增加,代码的重复性也会增加。肯定有更好的办法。想法?参考文献?我在StackOverflow上找不到类似的问题,但我相信它一定在这里......这似乎是一个必须要问的简单问题。

谢谢, 添

2 个答案:

答案 0 :(得分:6)

在最通用的情况下,我写的是:

projNameStr :: T24Report -> String
projName t24 = fromMaybe "" $ do
    title <- projTitle $ project t24
    zip title

关键是使用do块来分解处理所有Nothing个案例。

但是,在这种特殊情况下,由于链中只有两个Maybe,我很想缩短它:

projNameStr :: T24Report -> String
projName t24 = fromMaybe "" $ projTitle (project t24) >>= zip

这正是前一个示例在编译期间转换为的内容。通常那种人工贬值会让事情变得更糟,而不是更好。但在这种情况下,我很想接受这个,只是因为它的行数较短而且太多更多的工作要阅读。

答案 1 :(得分:6)

也许monad实例是为解决这个问题而构建的。如果你有一些对象,也许是X,也许是Y和也许是类型分别为Maybe a,Maybe b和Maybe c,你可以这样做

do x <- maybeX
   y <- maybeY
   z <- maybeZ
   return (x,y,z)

这将具有类型Maybe(a,b,c),如果三个Maybes中的任何一个为Nothing,则最终结果将为Nothing。

所以,在你的例子中,你会做这样的事情

projNameStr t24 = fromMaybe "" $ do t <- projTitle t24
                                    zip t