在 F# 中,我可以使用|
来分组匹配模式。例如:
let rec factorial n =
match n with
| 0 | 1 -> 1 // like in this line
| _ -> n * factorial (n - 1)
如何在 Haskell 中实现相同的语法?
在 F# 中,我可以使用|
来分组匹配模式。例如:
let rec factorial n =
match n with
| 0 | 1 -> 1 // like in this line
| _ -> n * factorial (n - 1)
如何在 Haskell 中实现相同的语法?
无法共享不同模式的相同右手边。但是,通常可以通过使用守卫而不是模式来解决这个问题,例如elem
。
foo x | x `elem` [A, C, G] = ...
| x `elem` [B, D, E] = ...
| otherwise = ...
elem
[0,1] = 1,因此会这样做。 - Jimmy Hoffa使用守卫:
factorial n
| n < 2 = 1
| otherwise = n * (factorial (n - 1))
使用模式匹配:
factorial 0 = 1
factorial 1 = 1
factorial n = n * (factorial (n - 1))
在上述答案的基础上,您可以(至少现在)使用守卫在单行上执行多个情况:
case name of
x | elem x ["Bob","John","Joe"] -> putStrLn "ok!"
"Frank" -> putStrLn "not ok!"
_ -> putStrLn "bad input!"
因此,输入"Bob"、"John"或"Joe"将给出"ok!"的结果,而"Frank"将是"not ok!",其他所有输入都将是"bad input!"
我不完全了解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没有像那样的语法。不过它确实有guards,正如其他人所提到的。
还要注意:
在Haskell中,在case语句中使用|
起到了不同的作用。|后面的语句作为guard。
case expr of
[x] | x < 2 -> 2
[x] -> 3
_ -> 4
如果这种语法要引入到Haskell中,就必须使用除|
之外的其他符号。我建议使用,
(向任何想将其添加到Haskell规范中的人提供此建议)。
unEither val = case val of
Left v, Right v -> v
目前这会产生“在 ,
上输入解析错误”
v
必须单态地绑定,在这些情况下,我认为RHS会多态地依赖于v
的类型。不过,如果没有分析真实的源代码,我就不确定了。 - luquifactorial 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)
并不是说这些选项比其他选项更好,只是在这里提出来。
|
符号视为 F# 中的when
关键字。 - MasterMastic