什么是 Haskell 的 Stream Fusion

Posted

技术标签:

【中文标题】什么是 Haskell 的 Stream Fusion【英文标题】:What is Haskell's Stream Fusion 【发布时间】:2010-10-09 08:22:09 【问题描述】:

以及如何使用它?

【问题讨论】:

您是否需要了解this post 尚未涵盖的内容?如果是这样,你能更具体一点吗? 相关:lambda.jstolarek.com/2013/04/haskell-as-fast-as-c-a-case-study 注意:还有一种叫做 List Fusion 的东西,它会通过许多内置函数自动发生:downloads.haskell.org/~ghc/7.4.2/docs/html/users_guide/… 并查看 conscientiousprogrammer.com/blog/2015/12/19/… 以了解如何检查它是否被使用(或尝试 @987654325 @)。 【参考方案1】:

Logan 指出的论文很棒,但有点难。 (只要问我的学生。)关于“流融合如何工作”的内容也很多,而“流融合是什么以及如何使用它”只有一小部分。

流融合解决的问题是编写的功能代码通常会分配中间列表,例如,要创建一个无限的节点编号列表,您可能会这样写

nodenames = map ("n"++) $ map show [1..]

天真的代码会分配一​​个无限的整数列表[1, 2, 3, ...],一个无限的字符串列表["1", "2", "3", ...],最终分配一个无限的名称列表["n1", "n2", "n3", ...]。分配太多了。

流融合所做的是将nodenames 之类的定义转换为使用递归函数的定义,该函数仅分配结果所需的内容。一般来说,消除中间列表的分配被称为森林砍伐

要使用流融合,您需要编写非递归列表函数,这些函数使用GHC ticket 915(mapfoldr 等)中描述的流融合库中的函数on) 而不是显式递归。该库包含所有 Prelude 函数的新版本,这些函数已被重写以利用流融合。显然,这些东西将在下一个 GHC 版本 (6.12) 中使用,但不在当前的稳定版本 (6.10) 中。如果你想使用库 Porges 在他的回答中有一个很好的简单解释。

如果您真的想了解流融合的工作原理,请发布另一个问题 --- 但要困难得多。

【讨论】:

是否有计划将此作为前奏列表的默认行为? 应用$和组合.的融合有区别吗? Prelude 的功能是否以某种方式被标记了,还是什么? IE。为什么它不适用于自制的递归函数? GHC 8.0.2 是否支持 Prelude 中的默认列表融合?【参考方案2】:

据我所知,与 Norman 所说的相反,流融合没有目前在 GHC 的基础中实现(即,您不能只使用 Prelude 函数)。如需更多信息,请参阅GHC ticket 915。

要使用流融合,您需要安装流融合库,导入 Data.List.Stream(您也可以导入 Control.Monad.Stream)并且只使用该模块中的函数而不是 Prelude 函数。这意味着导入 Prelude 会隐藏所有默认列表函数,而不是使用 [x..y] 构造或列表推导。

【讨论】:

【参考方案3】:

当 GHC 在 6.12 中默认使用这些新函数时,它们也会以非递归方式实现 [x..y] 和列表推导,这不是正确的吗?因为它们不是正确的行的唯一原因是它们是 internal 并且不是真正用 Haskell 编写的,而是更像关键字,为了速度和/或因为您无法重新定义那个语法。

【讨论】:

[ x .. y ] 不是关键字。在窗帘后面它被转换为enumFromTo x y,所以这并没有什么“神奇”。

以上是关于什么是 Haskell 的 Stream Fusion的主要内容,如果未能解决你的问题,请参考以下文章

Haskell 不会懒惰地评估交错

“为什么卡尔达诺用Haskell?难道IOHK将永远运行Cardano项目?

为什么是Haskell?

为什么 Haskell 是我们构建生产软件系统的首选

Haskell 模式匹配 - 它是啥?

haskell中的foldr地图是什么类型的?