[Haskell-beginners] Handling Maybes

Daniel Fischer daniel.is.fischer at googlemail.com
Wed May 25 12:30:18 CEST 2011


On Wednesday 25 May 2011 05:21:51, Elvio Toccalino wrote:
> Your second option may or may not be dangerous, but it sure looks
> tricky. I wouldn't use 'maybe' that way.
> How about this?
> 
> main = do val <- someIOFunc -- val is a Maybe String
>           maybe (someAction >> someOtherActionEtc)
>                 (\theValue -> putStrLn ("the string in reverse is " ++
> (reverse theValue))
>                 val
> 
> If you like point-free definitions:
> 
> main = do val <- someIOFunc -- val is a Maybe String
>           maybe (someAction >> someOtherActionEtc)
>                 (putStrLn . ("the string in reverse is " ++) . reverse)
>                 val
> 
> The difference is that my use of 'maybe' involves giving it actions, and
> not just pure functions.

I'd do that (perhaps in the form someIOFunc >>= maybe ... ...) or pattern-
match like Erik suggested.

I prefer not to pass long arguments to maybe, so if there's much to do with 
someIOFunc's result, either name the branches and use

    maybe nothingBranch justBranch val

or pattern-match

    case val of
      Nothing -> do
        something
        more
        ...
      Just v -> do
        foo v
        w <- bar v
        baz

(a bit more below)

> 
> On Tue, 2011-05-24 at 19:09 -0800, Christopher Howard wrote:
> > Since I started into Haskell, I frequently run into a scenario like
> > this: some function returns a Maybe value. If it is a Nothing, I want
> > to do one thing, but if it isn't, I want to do something with the
> > value encapsulated by the Maybe. But before I can use that value
> > (say, to print it) I've got to pull it out of the Maybe in a way that
> > satisfies the compiler. So one option is to use a separate function
> > with pattern matching, for example:
> > 
> > handleMaybeVal Nothing = do someAction
> > 
> >                             someOtherActionEtc
> > 
> > handleMaybeVal (Just a) = putStrLn ("The string in reverse is " ++
> > 
> >                                    (reverse a))
> > 
> > Or I can use the maybe function with a conditional
> > 
> > main = do val <- someIOFunc -- val is a Maybe String
> > 
> >           if val == Nothing

This introduces an Eq constraint, so you can't use that if someIOFunc 
produces functions (or anything else without an Eq instance).
The case pattern-matching avoids that constraint, and it does the unpacking 
in the same go too.

> >           
> >             then do someAction
> >             
> >               someOtherActionEtc
> >             
> >             else putStrLn ("The string in reverse is " ++
> >             
> >                           ((reverse . unpack) val))
> >   
> >   where unpack a = maybe
> >   
> >                      (error "unreachable error")
> >                      (\b -> b) a

That is

unpack = maybe (error "unrechable error") id

the function `maybe default id' is prominent enough to have its own name, 
it's `fromMaybe' (exported from Data.Maybe), so

unpack = fromMaybe (error "unreachable error")

> > 
> > The second option I like better, for some reason, but it is a bit
> > dangerous, as I have to double check my code to make sure the default
> > value passed to "maybe" cannot possibly be evaluated.

If you have that checked carefully, you could also use

unpack = fromJust

The difference to fromMaybe yourError is that fromJust produces a generic 
error message if your check failed, so if there are several 'fromJust's in 
the code, it doesn't tell you which of your checks failed, while your self-
supplied error should be easy to identify.

fromJust is a partial function, as such dangerous. Some people say you 
should *never* use it, but even without going so far, fromJust [and head, 
tail, ...] should only be used where you are *certain* that you can't get a 
Nothing. Generally, using it indicates not-so-good design somewhere.

> > (Alternatively,
> > I could pass in a regular default value, like a blank string, though
> > that is actually more dangerous in my mind because a bad value might
> > be used silently.)

That may be the right thing to do  in some circumstances, horribly wrong in 
others. But when supplying a default value is sensible, you should probably 
use a fromMaybe or maybe anyway.

> > 
> > Anyway: how do you pros go about handling situations like these?



More information about the Beginners mailing list