Haskell:foldl'累加器参数

时间:2012-06-20 01:22:02

标签: haskell lazy-evaluation

我一直在问一些关于严格性的问题,但我想我之前已经错过了这个标记。希望这更精确。

让我们说:

n = 1000000
f z = foldl' (\(x1, x2) y -> (x1 + y, y - x2)) z [1..n]

不改变f,我应该设置什么

z = ...

这样f z不会溢出堆栈? (即无论n的大小如何,都在恒定的空间内运行)

如果答案需要GHC扩展,那也没关系。


我的第一个想法是定义:

g (a1, a2) = (!a1, !a2)

然后

z = g (0, 0)

但我不认为g是有效的Haskell。

2 个答案:

答案 0 :(得分:9)

所以你的严格foldl'只会在折叠的每一步评估你的lambda的结果 Weak Head Normal Form ,即它只在最外面的构造函数中是严格的。因此,元组将被评估,但是元组中内部元素的添加可能会形成为thunk。这个in-depth answer实际上似乎可以解决您的确切情况。

W / R / T你的g:您正在考虑BangPatterns扩展,看起来像是

g (!a1, !a2) = (a1, a2)

并且在将它们返回元组之前评估a1和a2到WHNF。

你想要关注的不是你的初始累加器,而是你的lambda表达式。这将是一个很好的解决方案:

f z = foldl' (\(!x1, !x2) y -> (x1 + y, y - x2)) z [1..n]

编辑:在注意到您的其他问题后,我发现我没有仔细阅读过这个问题。你的目标是拥有“严格的数据”。那么,您的另一个选择是创建一个在其字段上具有严格标记的新元组类型:

data Tuple a b = Tuple !a !b

然后,当您在Tuple a b上进行模式匹配时,将评估ab

无论如何,您都需要更改功能。

答案 1 :(得分:3)

如果不改变f,你无能为力。如果f在对的类型中被重载,则可以使用严格对,但是当它处于f时,您将被锁定。编译器(严格性分析和转换)可以避免堆栈增长,这是一个小小的希望,但是你无法指望它。