什么是Haskell的Stream Fusion以及如何使用它?
答案 0 :(得分:62)
Logan指出的论文很棒,但有点困难。 (请问我的学生们。)这也是关于“流融合如何工作”以及“流融合是什么以及如何使用它”的一小部分。
流融合解决的问题是编写的功能代码经常分配中间列表,例如,创建一个无限的节点号列表,你可能会写
nodenames = map ("n"++) $ map show [1..]
朴素代码会分配一个无限的整数列表[1, 2, 3, ...]
,一个无限的字符串列表["1", "2", "3", ...]
,最终会有一个无限的名称列表["n1", "n2", "n3", ...]
。分配太多了。
什么流融合会将像nodenames
这样的定义转换为使用递归函数的东西,该递归函数仅分配结果所需的内容。通常,取消中间列表的分配称为砍伐森林。
要使用流融合,您需要编写非递归列表函数,它们使用GHC ticket 915中描述的流融合库中的函数(map
,{{ 1}}等等而不是显式递归。该库包含所有Prelude函数的新版本,这些函数已被重写以利用流融合。显然,这些东西将进入下一个GHC版本(6.12),但不是当前的稳定版本(6.10)。如果你想使用库Porges在他的回答中有一个很好的简单解释。
如果您真的想要解释流融合是如何工作的,请发布另一个问题---但这更难。
答案 1 :(得分:13)
据我所知,与Norman所说的相反,流融合是而不是目前在GHC的基础上实现(即你不能只使用Prelude函数)。有关详细信息,请参阅GHC ticket 915。
要使用流融合,您需要安装流融合库,导入Data.List.Stream(您也可以导入Control.Monad.Stream)并仅使用该模块中的函数而不是Prelude函数。这意味着导入Prelude隐藏所有默认列表函数,而不是使用[x..y]构造或列表推导。
答案 2 :(得分:-2)
不正确,当6.12中的GHC默认使用这些新函数时,它们还会以非递归方式实现[x..y]和列表推导吗?因为它们不是正确行的唯一原因是它们是内部并且不是真正用Haskell编写的,而是更像关键字,为了速度和/或因为你无法重新定义那种语法。