MultiCase
Inspired by http://stackoverflow.com/questions/7603509/haskell-syntax-for-or-in-case-expressions
It is proposed that Haskell allow multiple pattern matches in a case statement to map to a single right-hand-side expression.
factorial :: Int -> Int
factorial n = case n of
0, 1 -> 1
_ | n < 0 -> undefined
_ -> n * factorial (pred n)
-- without this suggested extension,
-- the cases of 0 and 1 would have to be handled separately.
If the right-hand-side expression utilizes bound variables from the pattern match, then all grouped pattern matches must bind the same variable.
unEither :: Either a a -> a
unEither eitherVal = case eitherVal of
Left v, Right v -> v
This is because only one of the pattern matches will occur. Clearly, the RHS cannot draw from multiple differing pattern matches. This would be an error.
-- this would be a scoping error
eitherSum :: Either Int Int -> Int
eitherSum eitherVal case eitherVal of
Left l, Right r -> l + r
An additional example:
-- modified example from Haskell School of Music
getDur :: Primitive a -> Dur
getDur p = case p of
ModDur (Tempo r) d -> d / r
Note d _, Rest d, ModDur _ d -> d
-- notice how we don't have to write `-> d` for
-- each of the 3 trivial cases; they all share the same RHS
-- layout rules should also permit
-- splitting the shared matches over multiple lines
getDur' :: Primitive a -> Dur
getDur' p = case p of
ModDur (Tempo r) d -> d / r
Note d _,
Rest d,
ModDur _ d -> d
The comma syntax would work for combining the outermost level of pattern matches in case statements. Something more interesting might be to allow nested options in patterns. Using `|` syntax:
case expr of
(GT|LT):foo -> expr1
EQ:bar -> expr2
-- This could be written more verbosely with Haskell's guard syntax:
case expr of
x:foo | x == GT || x == LT -> expr1
EQ:bar -> expr2
-- Or by simply duplicating the RHS
case expr of
GT:foo -> expr1
LT:foo -> expr1
EQ:bar -> expr2
Using `|` is a problem, however, since it would conflict with guard syntax. Using `,` is also a problem for nested options such as this, because it conflicts with pattern matching on tuples:
case expr of
(GT,LT):foo -> expr1
Nested case pattern options may be too complex to actually be useful. But it could be convenient to have it at the outermost level, in which case, the comma syntax should work decently. There would still be some ambiguity when guards are included
case expr of
pat1 | guard1, guard2 -> expr1
In the above case, it might be considered ambiguous whether or not guard2 is a guard, or whether it should actually be considered as pat2, another pattern.