为什么xs ++ acc在无限列表上使用foldr时有效,但是acc ++ xs却没有?

时间:2015-07-15 21:36:47

标签: haskell fold

我知道问题标题可能会产生误导,因为我没有在这里连接无限列表。随意提出更合适的内容。

以下是使用cycle的{​​{1}} Prelude函数的有效实现:

foldr

如果我们将fold_cycle :: [a] -> [a] fold_cycle xs = foldr step [] [1..] where step x acc = xs ++ acc 的操作数切换为++,则此功能不再有效。它会产生一个堆栈溢出,根据我的理解,这是尝试生成一个永无止境的表达式以供以后评估的结果。

我无法理解这背后的原因是什么。我的理由是,无论操作数的顺序如何,acc ++ xs都应评估foldr一次,生成新的累加器并在必要时再次评估step函数。为什么会有区别?

1 个答案:

答案 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

直观地说,我们必须跨过无数个括号来检查结果列表的第一个元素。