Подтвердить что ты не робот

Синтаксис Haskell для 'или' в случае выражений

В F # я могу использовать | для группировки случаев при сопоставлении шаблонов. Например,

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

Что такое синтаксис Haskell для того же?

4b9b3361

Ответ 1

Невозможно использовать одну и ту же правую сторону для разных шаблонов. Однако вы можете обойти это, используя защитные устройства вместо шаблонов, например, elem.

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

Ответ 2

с защитой:

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

с сопоставлением с образцом:

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

Ответ 3

Я не совсем знаком с F #, но в Haskell аргументы case позволяют вам сопоставлять шаблоны, привязывая переменные к частям выражения.

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

В теоретическом случае, что Haskell допускал одно и то же:

Поэтому было бы проблематично разрешить несколько привязок

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

Существуют редкие обстоятельства, при которых он может работать, используя ту же привязку:

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

И как в примере, который вы дали, он может работать нормально, если вы только сопоставляете литералы и ничего не связываете:

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

Однако:

Насколько я знаю, у Haskell нет такого синтаксиса. Однако у него есть стражи, как упоминалось другими.

Также обратите внимание:

Использование | в заявлении case выполняет другую функцию в Haskell. Заявление после | действует как охранник.

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

Итак, если этот тип синтаксиса должен быть введен в Haskell, ему нужно будет использовать что-то другое, кроме |. Я бы предложил использовать , (кому бы хотелось добавить это в спецификацию Haskell).

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

В настоящее время производится "ошибка синтаксического анализа на входе ,"

Ответ 4

Используя некоторые из приведенных выше ответов, вы можете (по крайней мере сейчас) использовать защитные устройства для выполнения нескольких случаев в одной строке:

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

Итак, вход "Боб", "Джон" или "Джо" даст вам "хорошо!", тогда как "Фрэнк" будет "не в порядке!", а все остальное будет "плохим вводом!"

Ответ 5

Здесь довольно буквальный перевод:

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

Представленные шаблоны также могут дать вам буквальный перевод.

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)

Не говоря, что это лучше, чем альтернативы. Просто указывая их.