Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Retrieving values from a chain of ADT's with Maybe's

I have some ADT's each of which may or not contain another ADT. I need to retrieve data from lower levels and I'm writing some very repetitive code which I am sure can be eliminated. I've looked at some example code in Real World Haskell and in "Learn You a Haskell For Great Good" but I can't quite figure it out. Here is an example with irrelevent details of the ADT's left out.

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

To retrieve the zip code from StreetAddress I've been ending up with this:

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

As the depth of the chain of objects increases, the repetitiveness of the code does too. There must be a better way. Ideas? References? I couldn't find a similar question on StackOverflow, but I believe it must be here...this seems like an simple problem that must have been asked.

Thanks, Tim

like image 963
tim93422 Avatar asked Jan 25 '13 19:01

tim93422


2 Answers

I'd write that, in the most generic case, something like:

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

The key point is using a do block to factor out handling all of the Nothing cases.

However, in this specific case, since there are only the two Maybes in the chain, I'd be tempted to shorten it a bit:

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

That's exactly what the previous example is converted to during compilation. Usually that sort of manual desugaring makes things worse, not better. But in this case, I would be tempted to go with this, just because it's a couple lines shorter and not too much more work to read.

like image 109
Carl Avatar answered Nov 15 '22 09:11

Carl


Maybe's monad instance is built for solving this exact problem. If you have some objects, maybeX, maybeY and maybeZ with types Maybe a, Maybe b and Maybe c respectively, you can do this

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

This will have the type Maybe (a,b,c), if any of the three Maybes was Nothing, the final result will be Nothing.

So, in your example, you would do something like this

projNameStr t24 = fromMaybe "" $ do t <- projTitle t24
                                    zip t
like image 21
Dirk Holsopple Avatar answered Nov 15 '22 09:11

Dirk Holsopple