【问题标题】:How stream fusion works in Haskell?流融合如何在 Haskell 中工作?
【发布时间】:2016-08-05 11:31:38
【问题描述】:

我可以在 Haskell 中编写属于流融合的自己的地图函数吗?

为什么列表上的递归迭代不受融合的影响?这完全扼杀了 Haskell 模式匹配的良好表现力:foo (x:xx) ...!

Prelude 循环函数是否融合?

【问题讨论】:

  • Prelude.map,就像许多Prelude 函数一样,需要构建/折叠融合,而不是流融合。这与流融合一样快,但涵盖的情况不同;特别是 build/foldr 融合不像 concatMap 这样的东西像流融合那样是病态的。
  • 要查看融合是如何工作的,请参阅此处的地图临时重写为 github.com/ghc/ghc/blob/master/libraries/base/GHC/Base.hs#L926 这允许删除带有通常 foldr/build 规则的列表 github.com/ghc/ghc/blob/master/libraries/base/GHC/Base.hs#L849 如果生成的内部 foldr 不与构建融合,则一切都恢复为标准我们在这里看到的递归映射 github.com/ghc/ghc/blob/master/libraries/base/GHC/Base.hs#L927
  • 仅供参考,这篇论文可读性很强:citeseer.ist.psu.edu/viewdoc/…
  • @Michael 有点跑题了:当所有循环操作都融合为一个时,是什么让文本比字符串快?
  • 我不确定所有因素,但Text 提供了更紧凑、更紧凑的表示。当然,在某些情况下,如果第一个 Char 存在,则整个文本都存在这一事实会使它“变慢”。例如。 T.readFile "/usr/share/dict/words >>= print . head 会更慢并使用更多内存。

标签: haskell optimization iteration


【解决方案1】:

Haskell 中的流融合是使用重写规则 (see the ghc documentation for more info) 完成的。这些是您可以使用RULES pragma 在代码中指定的规则。

重写规则的基本思想是,您指定一组可以在编译时重写代码的方式,例如,如果您将自己的 map 版本定义为 map',您可以执行类似的操作

{-# RULES 
   "map'/map'" forall f g xs. map' f (map' g xs) = map' (f . g) xs
  #-}

这引入了一个名为map'/map' 的重写规则。 这条规则的作用是,它将重写函数f 在列表上的每个映射,而g 又映射在一些xs 上,变成(f . g) 在这些xs 上的单个映射。

使用重写规则还有很多微妙之处。例如,您可以指定在编译器的哪个阶段应用规则,而编译器无法检查这些规则是否正确。

重写结果仍然经过类型检查,但如果你在重写规则中做了一些语义不正确的事情,那完全取决于你。

【讨论】:

  • 谢谢,但这只是答案的一部分。您错过了第二个问题 - 为什么 ghc 不能自行推断融合?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-11-04
  • 2015-01-31
  • 2016-12-18
  • 1970-01-01
  • 2014-04-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多