(New page: 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...)
Revision as of 04:18, 30 September 2011
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 <haskell> 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.