【问题标题】:Haskell infinite recursionHaskell 无限递归
【发布时间】:2016-09-11 14:30:28
【问题描述】:

以下函数计算斐波那契数列:

fib = 0 : 1 : (zipWith (+) fib (tail fib))

如果我们运行它,我们将得到一个无限列表,但是递归是如何工作的呢?如果函数不断调用自己,为什么它会在屏幕上打印数字?如果您能解释编译器如何管理调用,我将不胜感激。

【问题讨论】:

  • 用两个词懒惰编程

标签: list haskell recursion fibonacci infinite


【解决方案1】:

我画了一张图片,你可能会觉得有帮助。
请注意zipWtih op (x:xs) (y:xs) = (op x y):zipWith xs ys,这就是zipWtih 在列表中“移动”的方式。它正在读取元素并吐出总和:


这是更详细的分步评估。 (虽然我会粘贴那里的副本,但内存中只有一个副本。)对于我懒得写出来的东西,我会使用....

fib = 0:1:zipWith (+) fib (tail fib)
    = 0:1:zipWith (+) (0:1: .... ) (tail (0:1: .... )
    = 0:1:(0+1:zipWith (+) (1:(0+1: .... )) ( 0+1:..... ))
    = 0:1:1:zipWith (+) (1: ....) (......)

请注意,现在我们知道zipWith (+) fib (tail fib) = 1:.....

    = 0:1:1:zipWith (+) (1:1: ....) (1:......)
    = 0:1:1:(1+1):zipWith (+) (1:(1+1): .....) ((1+1):....)
    = 0:1:1:2:zipWith (+) (1:2: .....) (2:....)

我会快一点:

    = 0:1:1:2:(1+2):zipWith (+) (2: .....) (....)
    = 0:1:1:2:3     :zipWith (+) (2:3 .....) (3:....)
    = 0:1:1:2:3:(2+3):zipWith (+) (3:(2+3):.....) ((2+3):.....)
    = 0:1:1:2:3:5     :zipWith (+) (3:5:.....) (5:.....)
    = 0:1:1:2:3:5:8    :zipWith (+) (5:8:....) (8:......)
    = 0:1:1:2:3:5:8:13  :zipWith (+) (8:13:....) (13:......)
    = 0:1:1:2:3:5:8:13:21:zipWith (+) (13:21....) (21:......)

在每个阶段,zipWith 函数的最后两个参数就像指向fib 列表比我们现在更靠前(一个和两个位置)的指针。

【讨论】:

    【解决方案2】:

    一句话:懒惰。 Haskell 中的列表更像是一个生成器:它只会在其他东西需要时计算值。

    例如head [1 , 2+3] 不会执行添加,因为它不需要。类似地,如果我们递归地让ones = 1 : ones,那么head ones = head (1 : ones) = 1 不需要计算所有的尾部。

    你可以猜猜如果我们打印一对x会发生什么,定义如下:

    x = (n, fst x + 1)
    

    上面我们使用(惰性)对而不是(惰性)列表,但推理是相同的。除非其他东西需要,否则不要评估任何东西。

    【讨论】:

    • 您能否解释一下我提供的功能在最初的几次调用中是如何工作的?它什么时候决定停止调用自己并计算结果?在最后一次通话中zipWith (+) fib (tail fib) 会发生什么?该函数只返回 0:1:[]?
    • @RazvanMeriniuc 没有“最后一次呼叫”,也不会“停止呼叫自己”。关键是 Haskell 是 lazy 的,因此在需要计算之前不会对其进行评估。如果你从fib 中取出前 4 个数字,那么 Haskell 将计算表达式,直到它计算出 4 个元素,然后它会暂停计算。如果您随后取前 8 个数字,它将恢复计算以获取接下来的四个,然后重新挂起直到需要处理。这个过程没有“终点”。如果你试图拿下所有的数字(例如通过折叠),它永远不会完成。
    猜你喜欢
    • 2011-08-16
    • 2017-02-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-14
    • 2014-03-24
    • 2018-08-15
    相关资源
    最近更新 更多