5

我有一些 ADT,每个 ADT 可能包含或不包含另一个 ADT。我需要从较低级别检索数据,并且我正在编写一些非常重复的代码,我确信这些代码可以被消除。我在 Real World Haskell 和“Learn You a Haskell For Great Good”中查看了一些示例代码,但我不太明白。这是一个关于 ADT 被遗漏的无关细节的示例。

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

要从 StreetAddress 中检索邮政编码,我一直这样做:

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

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

谢谢,蒂姆

4

2 回答 2

6

在最一般的情况下,我会这样写:

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

关键是使用一个do块来分解处理所有的Nothing情况。

但是,在这种特定情况下,由于链中只有两个Maybes,因此我很想将其缩短一点:

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

这正是上一个示例在编译期间转换为的内容。通常这种手动脱糖会使事情变得更糟,而不是更好。但在这种情况下,我很想这样做,只是因为它短了几行,而且阅读量也不

于 2013-01-25T19:27:00.267 回答
6

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

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

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

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

projNameStr t24 = fromMaybe "" $ do t <- projTitle t24
                                    zip t
于 2013-01-25T19:46:57.517 回答