Haskell syntax for 'or' in case expression

2020-03-01 02:49发布

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

let rec factorial n = 
  match n with
  | 0 | 1 -> 1                 // like in this line
  | _ -> n * factorial (n - 1)

What's the Haskell syntax for the same?

5条回答
时光不老,我们不散
2楼-- · 2020-03-01 03:13

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))
查看更多
够拽才男人
3楼-- · 2020-03-01 03:31

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          = ...
查看更多
女痞
4楼-- · 2020-03-01 03:32

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!"

查看更多
5楼-- · 2020-03-01 03:34

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.

查看更多
太酷不给撩
6楼-- · 2020-03-01 03:38

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 ,"

查看更多
登录 后发表回答