为啥 Haskell 中的递归习语是“'n+1' and 'n'”而不是“'n' and 'n-1'”?
Posted
技术标签:
【中文标题】为啥 Haskell 中的递归习语是“\'n+1\' and \'n\'”而不是“\'n\' and \'n-1\'”?【英文标题】:Why is the recursion idiom in Haskell "'n+1' and 'n'" and not "'n' and 'n-1'"?为什么 Haskell 中的递归习语是“'n+1' and 'n'”而不是“'n' and 'n-1'”? 【发布时间】:2011-02-16 14:26:08 【问题描述】:我正在阅读 Graham Hutton 的 Haskell 书,在他的递归章节中,他经常在“n+1”上进行模式匹配,如下所示:
myReplicate1 0 _ = []
myReplicate1 (n+1) x = x : myReplicate1 n x
为什么是这样,而不是以下,哪个 (1) 在功能上看起来相同,(2) 在理解递归发生的事情方面更直观:
myReplicate2 0 _ = []
myReplicate2 n x = x : myReplicate2 (n-1) x
这里有什么我遗漏的吗?还是只是风格问题?
【问题讨论】:
【参考方案1】:我认为它背后的想法是:我们可以像这样为自然数 (0, 1, ...) 定义一个类型:
data Natural = Z -- zero
| S Natural -- one plus a number; the next number; the "successor"
0 = Z
、1 = S Z
等等。这个系统被称为 Peano 算术,它几乎是数学中的一个标准,作为“数字”实际上是什么的(a 的起点)定义。您可以继续将Integer
s 定义为Natural
s 的对(-ish),依此类推。
当你这样做时,使用这样的模式匹配就变得很自然了:
myReplicate1 Z _ = []
myReplicate1 (S n) x = x : myReplicate1 n x
我认为(这只是一个猜测)n+1
模式背后的想法是我刚才描述的机器版本。所以,n+1
被认为类似于模式S n
。如果你这样想,n+1
模式看起来很自然。这也清楚地说明了为什么我们有 n >= 0
的附带条件。我们只能使用Natural
类型来表示n >= 0
。
【讨论】:
【参考方案2】:N+K 模式也有不同的严格含义。
例如:
f (n+1) = Just n
g n = Just (n-1)
f 对它的第一个参数是严格的,g 不是。这对于 n+k 模式没有什么特别之处,但适用于所有模式。
【讨论】:
【参考方案3】:第一个函数中的那些是 n+k 模式(应该避免!)。两个函数做同样的事情,除了 n+k 一个不匹配负数。但是,建议使用后一个,如果你故意不想要负数,可以采用,因为 n+k 模式被分解为removed anyways。
所以不,你什么都没有错过,这确实是风格问题,但我很少在野外看到 n+k 模式。
【讨论】:
换句话说,这是风格问题,第一种风格已被弃用。 :) 它们实际上并不相同。 n+k 模式不会匹配负数。 哎呀,没想到!谢谢,sepp,我编辑了我的答案! 非常有趣 - 我想我错过了一些东西(n >= 0 位)。这是一种奇怪的魔法行为。我认为反对删除它的一个论点是“一些 Haskell 书籍使用它”很有趣 :)【参考方案4】:myReplicate n x = take n (repeat x)
完成并完成。 :D
【讨论】:
【参考方案5】:n+k 模式仅在 n>=0 时匹配。因此,在您的 myReplicate1 中,n+1 模式将仅匹配正数,而负数 n 将导致非穷举模式异常。在 myReplicate2 中,负数 n 将创建一个无限列表。
因此,换句话说,当您不希望模式匹配负数时,您可以使用 n+k 模式,但使用保护会更清晰。
【讨论】:
以上是关于为啥 Haskell 中的递归习语是“'n+1' and 'n'”而不是“'n' and 'n-1'”?的主要内容,如果未能解决你的问题,请参考以下文章