在 Haskell 中,在这个列表理解中使用 takeWhile 或使用"regular"不等式有什么区别?



我正在努力学习Haskell(非常好),我正在做的许多不同的事情之一是在测试我的勇气时尝试解决一些Project Euler问题。

在做一些基于斐波纳契的问题时,我偶然发现并开始玩斐波那契序列的递归无限列表版本:

fibs = 1 : 2 : zipWith (+) fibs (tail fibs)

对于其中一个PE问题,我需要提取小于4000000的偶数Fibonacci数的子序列。我决定用列表理解来做这件事,在我摆弄代码的过程中,我偶然发现了一些我不太理解的东西;我想,是我对哈斯克尔懒惰的评估方案的理解不力,才使事情变得复杂。

以下理解很好:

[x | x <- takeWhile (<= 4000000) fibs, even x]

下一个理解永远旋转;因此,我进行了检查,并将输出返回到stdout,当它停止在正确的位置时,它似乎永远在继续评估递归定义的列表,而在达到上限值后没有完成;表示列表中的最后一个项目用逗号打印,但不存在其他列表项目或结束方括号:

[x | x <- fibs, x <= 4000000, even x]

那么,在无限列表中运行良好的各种函数所使用的秘密酱汁究竟是什么呢?

函数takeWhile不断获取输入列表中的元素,直到它到达不满足谓词的第一个元素,然后它停止。只要至少有一个元素不满足谓词,takeWhile就会将无限列表变成有限列表。

你的第一个表情是

继续获取这个无限列表中的元素,直到找到一个大于4000000的元素,然后停止。在输出中包含每个元素(如果是偶数)。

第二个表达式显示

继续获取这个无限列表中的元素。如果输出中的每个元素小于或等于4000000并且是偶数,则将其包含在内。

当您观察到一个永远挂起的输出时,该函数正忙于生成更多的斐波那契数,并检查它们是否小于或等于4000000。它们都没有,这就是为什么屏幕上没有打印任何内容,但该功能无法知道它不会遇到列表后面的一个小数字,所以它必须不断检查。

最新更新