Haskell:foldl'累加器参数
我一直在问严格的几个问题,但我认为我之前错过了这个标记。 希望这更准确。
可以说我们有:
n = 1000000
f z = foldl' ((x1, x2) y -> (x1 + y, y - x2)) z [1..n]
不改变f
,我应该设置什么
z = ...
所以fz
不会溢出堆栈? (即不管n的大小如何都在恒定的空间中运行)
它可以,如果答案需要GHC扩展。
我的第一个想法是定义:
g (a1, a2) = (!a1, !a2)
接着
z = g (0, 0)
但我不认为g
是有效的Haskell。
所以你严格的foldl'
只会在折叠的每一步中评估你的lambda的结果为弱头标准形式,也就是说它只在最外层的构造函数中是严格的。 因此,元组将被评估,但是元组内的这些添加可能会形成为thunk。 这个深入的答案实际上似乎解决你在这里的确切情况。
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 ab
上匹配模式时, a
和b
将被评估。
无论如何你都需要改变你的功能。
没有改变f
你就无能为力。 如果f
在对中的类型中超载,那么可以使用严格的对,但按照它的规定,你会被锁定到f
所做的。 编译器(严格分析和转换)可以避免堆栈增长,但没有什么值得您信赖的。