Can I have a case where the alternatives contain expressions?
There are several approaches to this problem.
We can do this nicely with a function implemented in Haskell:
select :: a -> [(Bool, a)] -> a select def = maybe def snd . List.find fst -- = fromMaybe def . lookup True -- = maybe def id . lookup True select exDefault [(cond1, ex1), (cond2, ex2), (cond3, ex3)]
Unfortunately this function is not in the Prelude. It is however in the utility-ht package.
Alternative implementations are
if' :: Bool -> a -> a -> a if' True x _ = x if' False _ y = y select'' = foldr (uncurry if')
The implementation of select'' makes clear that select can be considered as nested if s. The functional if' is also useful in connection with zipWith3 since zipWith3 if' merges two lists according to a list of conditions. See if-then-else.
Alternatively you can unroll foldr and write
if' cond1 ex1 $ if' cond2 ex2 $ if' cond3 ex3 $ exDefault
If you use if' in infix form, you may call it ? like in C, then because of partial application it will work nicely together with '$' for the else clause.
infixl 1 ? (?) :: Bool -> a -> a -> a (?) = if' cond1 ? ex1 $ cond2 ? ex2 $ cond3 ? ex3 $ exDefault
You can make use of some syntactic sugar of Haskell, namely of guards.
case () of _ | cond1 -> ex1 | cond2 -> ex2 | cond3 -> ex3 | otherwise -> exDefault
Alternatively, one could simply factor out a function(/value) and use guards in the argument patterns.
An alternative sugarful approach is to use list comprehensions.
head $ [ ex1 | cond1 ] ++ [ ex2 | cond2 ] ++ [ ex3 | cond3 ] ++ [ exDefault ]
The MultiWayIf extension lets you write code similar to a case () of _ form, using only the word if . To enable it, add to the top of a .hs file, run ghci with ghci -XMultiWayIf, or add MultiWayIf to the default-extensions in your .cabal file.
if | guard1 -> expr1 | . | guardN -> exprN