我对像下面这样的无限列表的运行时性能很好奇:
fibs = 1 : 1 : zipWith (+) fibs (tail fibs)
这将创建斐波那契数列的无限列表。
我的问题是,如果我执行以下操作:
takeWhile (<5) fibs
fibs
评估列表中的每个术语多少次?似乎由于takeWhile
检查列表中每个项目的谓词函数,fibs
列表将多次评估每个术语。前 2 个学期免费提供。当takeWhile
想要评估
(<5)
第三个元素时,我们会得到:
1 : 1 : zipWith (+) [(1, 1), (1)] => 1 : 1 : 3
现在,一旦takeWhile
想要评估(<5)
第 4 个元素:递归性质fibs
将再次构造列表,如下所示:
1 : 1 : zipWith (+) [(1, 2), (2, 3)] => 1 : 1 : 3 : 5
当我们想要评估第 4 个元素的值时,似乎需要再次计算第 3 个元素。此外,如果谓词 intakeWhile
很大,则表明该函数正在执行更多所需的工作,因为它多次评估列表中的每个前面的元素。我的分析是正确的还是 Haskell 做了一些缓存来防止这里的多次评估?