[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