我有一些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上找不到类似的问题,但我相信它一定在这里......这似乎是一个必须要问的简单问题。
谢谢, 添
答案 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