【问题标题】:What are "n+k patterns" and why are they banned from Haskell 2010?什么是“n+k 模式”,为什么它们在 Haskell 2010 中被禁止?
【发布时间】:2011-04-14 11:57:07
【问题描述】:

在阅读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 模式?

【问题讨论】:

  • 若想了解 n+k 模式的为什么,请查看这篇出色的博文:blog.sigfpe.com/2007/07/data-and-codata.html
  • 对于仍然想使用 n+k 模式的人(我在看着你,Erik Meijer),有-XNPlusKPatterns{-# LANGUAGE NPlusKPatterns #-}

标签: haskell functional-programming


【解决方案1】:

什么是 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

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

【讨论】:

  • 很好的答案!我对 Haskell 很陌生,所以我的下一个问题是:为什么类型检查器允许该模式并且至少不发出警告?在这种情况下,它必须知道该代码缺少某些情况。
  • 你可以很容易地修复类型签名:let f 0 = 0 ; f n | toInteger n &gt;= 5 = n' where n' = n - 5.
  • 为什么 0
  • 你也可以把lets in模式守卫,所以你也可以写let f 0 = 0; f n | let n' = n - 5, n' &gt;= 0 = n'
【解决方案2】:

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

如需更多关于一般 n+k 模式的背景信息,请在 pattern matching 上向下滚动至本页 3/5 左右,或查看简短的 post

【讨论】:

    猜你喜欢
    • 2011-01-14
    • 2012-05-15
    • 2013-05-11
    • 1970-01-01
    • 1970-01-01
    • 2012-01-24
    • 2011-01-15
    • 1970-01-01
    相关资源
    最近更新 更多