Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simplifying nested Maybe pattern matching

I have the following construct in my code:

f :: Maybe A -> X
f a = case a of
  Nothing -> x
  (Just b) -> case b of
    Nothing -> y
    (Just c) -> case c of
      Nothing -> z
      (Just d) -> d

I'm not seeing an obvious way to simplify this instead of using nested maybe functions, which wouldn't make the whole thing look much better. Are there any clever - but still understandable - tricks that would help make this construct more "elegant"?

like image 692
Philip Kamenarsky Avatar asked Oct 29 '13 10:10

Philip Kamenarsky


3 Answers

Why did the code construct a Maybe (Maybe (Maybe X)) value in the first place? Unpacking such a value isn't nice, but the real question is, why there even is such a value. Maybe the code would better avoid all those nested Maybes.

If you really need to have such a value and need to do different things in all the Just/Nothing cases you'll have to write them all down. But instead of several nested case statements you could combine them into one big pattern match:

f Nothing                = x
f (Just Nothing))        = y
f (Just (Just Nothing))  = z 
f (Just (Just (Just d))) = d
like image 191
sth Avatar answered Oct 18 '22 10:10

sth


Despite your constraint about not using maybe, I think this looks quite nice:

f = maybe x (maybe y (maybe z id))

or even better, as @pat suggests in his comment:

f = maybe x . maybe y . maybe z $ id
like image 40
nickie Avatar answered Oct 18 '22 10:10

nickie


UPDATED 2

Monad Either is for you

import Data.Maybe (maybe)

maybeE :: e -> Maybe a -> Either e a
maybeE e = maybe (Left e) Right

f :: Maybe (Maybe (Maybe d)) -> Either e d
f a  =   maybeE x a 
     >>= maybeE y
     >>= maybeE z

UPDATED 3

If we want to have not Either type, we could rewrite function:

import Data.Either(either)

either' = either id id

f :: Maybe (Maybe (Maybe d)) -> d
f a = either' $ maybeE x a 
            >>= maybeE y
            >>= maybeE z
like image 29
viorior Avatar answered Oct 18 '22 10:10

viorior