开发者

Haskell syntax for 'or' in case expressions

In F#, I can use | to group cases when pattern matching. For example,

let rec factorial n = 
  match n with
  | 0 | 1 -> 1 开发者_Python百科                // like in this line
  | _ -> n * factorial (n - 1)

What's the Haskell syntax for the same?


There is no way of sharing the same right hand side for different patterns. However, you can usually get around this by using guards instead of patterns, for example with elem.

foo x | x `elem` [A, C, G] = ...
      | x `elem` [B, D, E] = ...
      | otherwise          = ...


with guards:

factorial n
    | n < 2 = 1
    | otherwise = n * (factorial (n - 1))

with pattern matching:

factorial 0 = 1
factorial 1 = 1
factorial n = n * (factorial (n - 1))


I'm not entirely familiar with F#, but in Haskell, case statements allow you to pattern match, binding variables to parts of an expression.

case listExpr of
    (x:y:_) -> x+y
    [x]     -> x
    _       -> 0

In the theoretical case that Haskell allowed the same:

It would therefore be problematic to allow multiple bindings

case listExpr of
    (x:y:_) | [z] -> erm...which variables are bound? x and y? or z?

There are rare circumstances where it could work, by using the same binding:

 unEither :: Either a a -> a
 unEither val = case val of
   Left v | Right v -> v

And as in the example you gave, it could work alright if you only match literals and do not bind anything:

case expr of
  1 | 0 -> foo
  _     -> bar

However:

As far as I know, Haskell does not have syntax like that. It does have guards, though, as mentioned by others.

Also note:

Using | in the case statement serves a different function in Haskell. The statement after the | acts as a guard.

case expr of
  [x] | x < 2 -> 2
  [x] -> 3
  _ -> 4

So if this sort of syntax were to be introduced into Haskell, it would have to use something other than |. I would suggest using , (to whomever might feel like adding this to the Haskell spec.)

unEither val = case val of
  Left v, Right v -> v

This currently produces "parse error on input ,"


Building on some of the above answers, you can (at least now) use guards to do multiple cases on a single line:

case name of
    x | elem x ["Bob","John","Joe"] -> putStrLn "ok!"
    "Frank"                         -> putStrLn "not ok!"
    _                               -> putStrLn "bad input!"

So, an input of "Bob", "John", or "Joe" would give you an "ok!", whereas "Frank" would be "not ok!", and everything else would be "bad input!"


Here's a fairly literal translation:

factorial n = case n of
    0 -> sharedImpl
    1 -> sharedImpl
    n -> n * factorial (n - 1)
    where
        sharedImpl = 1

View patterns could also give you a literal translation.

isZeroOrOne n = case n of
    0 -> True
    1 -> True
    _ -> False

factorial1 n = case n of
    (isZeroOrOne -> True) -> 1
    n -> n * factorial (n - 1)

factorial2 n = case n of
    (\n -> case n of { 0 -> True; 1 -> True; _ -> False }) -> 1
    n -> n * factorial (n - 1)

Not saying that these are better than the alternatives. Just pointing them out.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜