我知道问题标题可能会产生误导,因为我没有在这里连接无限列表。随意提出更合适的内容。
以下是使用cycle
的{{1}} Prelude
函数的有效实现:
foldr
如果我们将fold_cycle :: [a] -> [a]
fold_cycle xs = foldr step [] [1..]
where step x acc = xs ++ acc
的操作数切换为++
,则此功能不再有效。它会产生一个堆栈溢出,根据我的理解,这是尝试生成一个永无止境的表达式以供以后评估的结果。
我无法理解这背后的原因是什么。我的理由是,无论操作数的顺序如何,acc ++ xs
都应评估foldr
一次,生成新的累加器并在必要时再次评估step
函数。为什么会有区别?
答案 0 :(得分:8)
foldr
根本不评估累加器。 fold_cycle
正是因为它不一定会评估acc
。
fold_cycle [1, 2]
缩减为
[1, 2] ++ ([1, 2] ++ ([1, 2] ++ ([1, 2] ++ ...
这允许我们评估结果的前缀,因为++
允许我们遍历第一个参数而不评估第二个参数。
如果我们使用step _ acc = acc ++ xs
,则上述表达式中的括号与左侧而不是右侧相关联。但由于我们有无限多的追加,表达式最终会像这样:
((((((((((((((... -- parentheses all the way down
直观地说,我们必须跨过无数个括号来检查结果列表的第一个元素。