Синтаксис Haskell для 'или' в случае выражений
В F # я могу использовать |
для группировки случаев при сопоставлении шаблонов. Например,
let rec factorial n =
match n with
| 0 | 1 -> 1 // like in this line
| _ -> n * factorial (n - 1)
Что такое синтаксис Haskell для того же?
Ответы
Ответ 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)
Не говоря, что это лучше, чем альтернативы. Просто указывая их.