Haskell:foldl'累加器参数

Posted

技术标签:

【中文标题】Haskell:foldl\'累加器参数【英文标题】:Haskell: foldl' accumulator parameterHaskell:foldl'累加器参数 【发布时间】:2012-06-20 01:22:02 【问题描述】:

我一直在问一些关于严格性的问题,但我想我之前没记错。希望这更准确。

假设我们有:

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。

【问题讨论】:

【参考方案1】:

因此,您的严格 foldl' 只会在折叠到 Weak Head Normal Form 的每个步骤中评估您的 lambda 的结果,即它仅在最外层的构造函数中是严格的。因此 tuple 将被评估,但是 inside 元组的那些添加可能会构建为 thunk。这个in-depth answer 实际上似乎在这里解决了您的确切情况。

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

g (!a1, !a2) = (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

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

【讨论】:

【参考方案2】:

如果不更改 f,您将无能为力。如果 f 在配对类型中被重载,您可以使用严格配对,但就目前而言,您被锁定在 f 所做的事情中。编译器(严格性分析和转换)可以避免堆栈增长,但没有什么可以指望的。

【讨论】:

以上是关于Haskell:foldl'累加器参数的主要内容,如果未能解决你的问题,请参考以下文章

我不确定我是否理解haskell中foldl函数的类型定义

使用`foldl`实现Haskell的`take`函数

Haskell 的 foldr/l 和 Clojure 的 reduce

Haskell:一个组合案例

在haskell中故意定义无限类型

Haskell入门篇九:高阶函数(中)