Merge multiple cases in Haskell

Viewed 162

With a case _ of syntax like this:

fun a b c =
    case (a, b, c) of
        (Just True, Just _, _) -> foo
        (Just True, _, Just _) -> foo
        _                      -> bar

Can I merge the first two conditions and avoid repeating foo?

Alternatively, is there any other (cleaner) way to express that I want to run foo if and only if a is Just True and either b or c are not Nothing?

3 Answers

You can do something like this:

fun a b c = case (a, b <|> c) of
    (Just True, Just _) -> foo
    _ -> bar

Of course, that's just hiding the extra match in (<|>), but you gotta pay the piper some time.

If b and c do not have the same type, you can cause them to with the ill-named void.

Let me complement the other answers with a "boring" alternative:

fun a b c = let
   foo' = foo
   in case (a, b, c) of
      (Just True, Just _, _) -> foo'
      (Just True, _, Just _) -> foo'
      _                      -> bar

This might or might not answer the intended question, depending on the actual goal.

If the goal was to avoid writing two patterns in the case, this of course fails to meet the goal.

If instead the goal was to avoid repeating foo, which could be a very long expression (e.g., a long do block in some monad), this meets the goal by giving a short name to the long expression.

Don't know if this looks cleaner but you could use the good old pal if too:

fun a b c =
   if a == Just True && (isJust b || isJust c) 
      then foo
      else bar

or use guards

fun a b c =
   case a of
       Just True | isJust b || isJust c -> foo
       _ -> bar

without case:

fun (Just True) b c | isJust b || isJust c = foo
fun _ _ _ = bar

all is using isJust and as Daniel pointed out those too will give the piper it's due (pattern match).

Related