Now generalize it to more than two cases, or one where the second case needs to pattern match too. The magic of pattern guards is not in a single guarding expression, but in a function with many different cases which use pattern guards.
MonadPlus is your friend, especially if (fail s) is mzero. I tend to use something like the following "design pattern" to "lift" pattern match failure/case handling into the expression world: import Data.Maybe import Control.Monad clunky' env vars = fromJust $ do (var1:var2:vars) <- return vars val1 <- lookup var1 env val2 <- lookup var2 env return (val1 + val2) `mplus` do [var1] <- return vars -- .. some stuff .. return 1 `mplus` do [] <- return vars -- .. more stuff .. return 2 -- *Main> let env=[(1,5),(2,7)] *Main> clunky' env [1,2] 12 *Main> clunky' env [0] 1 *Main> clunky' env [] 2 Very handy for syntax-oriented programming and if combined with non-deterministic state transformers, as in parsers, type systems and the like. cheers, claus