【问题标题】:How can I fuse two maps over the same list?如何在同一个列表中融合两张地图?
【发布时间】:2012-09-03 04:29:09
【问题描述】:

我们可以在表达式中融合两个遍历列表xs

(map f xs, map g xs)

像这样

unzip (map (\x -> (f x, g x)) xs)

有没有关于自动执行这种融合的研究?

(如果其中一个返回的列表先于另一个被消耗,则存在空间泄漏的风险。我更感兴趣的是防止对xs 的额外遍历而不是节省空间。)

编辑:我实际上并不打算将融合应用到实际的内存中 Haskell 列表中,根据 unzip 是否可以与其消费者融合,这种转换可能没有意义。我有一个我知道unzip 可以融合的设置(请参阅“FlumeJava:简单、高效的数据并行管道”)。

【问题讨论】:

  • 不是自动的,但还是不错的:squing.blogspot.com/2008/11/beautiful-folding.html
  • 除非这个结果与其他东西融合,否则创建对和解压缩它们的开销将大于额外遍历的成本。
  • @augustss 如果遍历是在一个巨大的文件上,则不会!我不打算将其应用于实际列表。
  • 解压缩将遍历与地图长度相同的列表,因此您不会保存遍历。现在,如果您关心节省融合为您提供的空间,那么它可以产生巨大的影响。我从你的评论中推断出你对太空不感兴趣,但我发现这并不是你所说的。 :)
  • “防止对 xs 的额外遍历”也可以通过大多数迭代器样式的包来实现。

标签: haskell fusion


【解决方案1】:

也不是全自动的,但你可以给 GHC 一个类似的重写规则列表。请参阅 7.14 Rewrite rules 和 Using rules。然后编译器在编译时使用这些规则来优化你的程序。 (请注意,编译器绝不会检查规则是否有意义。)

编辑:为了给这个特定问题举个例子,我们可以这样写:

{-# OPTIONS_GHC -fenable-rewrite-rules -ddump-rule-firings -ddump-rule-rewrites #-}

import Data.Char

{-# RULES
"map/zip" forall f g xs. (,) (map f xs) (map g xs) = unzip (map (\x -> (f x, g x)) xs)
   #-}

main :: IO ()
main = let x = "abCD" in
        print $ (,) (map toUpper x) (map toLower x)

(规则中的顶级函数名称为(,) :: a -> b -> (a, b))。编译时,您将看到规则是如何应用的。选项 dump-rule-firings 会在应用规则时显示一条消息,-ddump-rule-rewrites 会详细显示每个规则应用程序 - 请参阅 7.14.6. Controlling what's going on in rewrite rules。

【讨论】:

  • 我认为我们不能编写规则来匹配这些表达式。 GHC 规则必须以函数名开头。
【解决方案2】:

我设法找到了两个资源,它们至少简要地提到了类似 fusion (un-)zip 的功能:

约瑟夫·斯文宁森。 《累积参数&类Zip函数的捷径融合》 http://www.cse.chalmers.se/~josefs/publications/fusion.pdf

邓肯·考茨。 “流融合:协导序列类型的实用快捷融合” https://community.haskell.org/~duncan/thesis.pdf

不过,两种资源都没有明确提到这种“兄弟融合”。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2023-03-06
  • 2020-05-27
  • 2015-11-22
  • 1970-01-01
  • 2020-03-24
  • 2020-06-20
  • 1970-01-01
  • 2017-08-22
相关资源
最近更新 更多