繁体   English   中英

Haskell无限递归

[英]Haskell infinite recursion

以下函数计算Fibonacci序列:

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

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

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

pic用彩色指针


这是一个更详细的逐步评估。 (虽然我会粘贴那些内容的副本,但内存中只有一个副本。)我会使用....因为我不能写出来的东西。

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列表中比我们目前更进一步。

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

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

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

x = (n, fst x + 1)

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM