什么是“n + k模式”,为什么它们被禁止使用Haskell 2010?

时间:2010-09-20 03:44:43

标签: haskell functional-programming

阅读Wikipedia's entry on Haskell 2010时,我偶然发现了这个:

-- using only prefix notation and n+k-patterns (no longer allowed in Haskell 2010)
factorial 0 = 1
factorial (n+1) = (*) (n+1) (factorial n)

“n + k模式”是什么意思?我想这是第二行,但我不知道它可能有什么问题。任何人都可以解释那里的问题是什么?为什么Haskell 2010中不允许使用这些n + k模式?

2 个答案:

答案 0 :(得分:62)

什么是n + k模式?看看这个:

$ ghci
GHCi, version 6.12.3: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Loading package ffi-1.0 ... linking ... done.
Prelude> let f 0 = 0 ; f (n+5) = n
Prelude> :t f
f :: (Integral t) => t -> t
Prelude> f 0
0
Prelude> f 1
*** Exception: <interactive>:1:4-24: Non-exhaustive patterns in function f

Prelude> f 2
*** Exception: <interactive>:1:4-24: Non-exhaustive patterns in function f

Prelude> f 3
*** Exception: <interactive>:1:4-24: Non-exhaustive patterns in function f

Prelude> f 4
*** Exception: <interactive>:1:4-24: Non-exhaustive patterns in function f

Prelude> f 5
0
Prelude> f 6
1

它们在模式匹配方面基本上是一个非常特殊的例子,它只适用于数字,而且确实......好吧,让我们只是礼貌并称之为“意想不到的事物”。

这里我有一个函数f,它有两个子句。第一个子句匹配0,仅匹配0。第二个子句匹配任何值为5或更大的Integral类型的值。绑定名称(在这种情况下为n)的值等于您传递的数字减去5.至于为什么它们已从Haskell 2010中删除,我希望您现在可以看到原因有点想法。 (提示:考虑“最少惊喜的原则”以及它在这里可能适用或不适用。)


已编辑添加:

现在出现的一个自然问题是这些结构是被禁止的,“你用什么来代替它们?”

$ ghci
GHCi, version 6.12.3: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Loading package ffi-1.0 ... linking ... done.
Prelude> let f 0 = 0 ; f n | n >= 5 = n - 5
Prelude> :t f
f :: (Num t, Ord t) => t -> t
Prelude> f 0
0
Prelude> f 1
*** Exception: <interactive>:1:4-33: Non-exhaustive patterns in function f

Prelude> f 2
*** Exception: <interactive>:1:4-33: Non-exhaustive patterns in function f

Prelude> f 3
*** Exception: <interactive>:1:4-33: Non-exhaustive patterns in function f

Prelude> f 4
*** Exception: <interactive>:1:4-33: Non-exhaustive patterns in function f

Prelude> f 5
0
Prelude> f 6
1

你会从类型陈述中注意到这些并不完全相同,但是使用防护装置“足够相同”。在任何在多个地方使用它的代码中,在表达式中使用n-5可能会变得乏味且容易出错。答案是使用where条款:

Prelude> let f 0 = 0 ; f n | n >= 5 = n' where n' = n - 5
Prelude> :t f
f :: (Num t, Ord t) => t -> t
Prelude> f 0
0
Prelude> f 5
0
Prelude> f 6
1

where子句允许您在多个位置使用计算表达式,而不会有错误输入的风险。在功能定义的两个不同位置编辑边界值(在这种情况下为5)仍然存在烦恼,但我个人认为这对于认知理解的增加来说是一个很小的代价。


进一步编辑添加:

如果您希望let个句子超过where条款,则可以选择其他方式:

Prelude> let f 0 = 0 ; f n | n >= 5 = let n' = n - 5 in n'
Prelude> :t f
f :: (Num t, Ord t) => t -> t
Prelude> f 0
0
Prelude> f 5
0

就是这样。我现在真的完成了。

答案 1 :(得分:4)

trinithis提供的链接是正确的; n + k模式不再包含在Haskell规范中。

有关n + k模式的更多背景信息,请在pattern matching上向下滚动此页面的大约3/5,或查看此简短post