我们可以在表达式
中的列表xs
上融合两次遍历
(map f xs, map g xs)
喜欢这样
unzip (map (\x -> (f x, g x)) xs)
是否有自动执行此类融合的研究?
(如果其中一个返回的列表在另一个之前消耗,则存在创建空间泄漏的风险。我更有兴趣防止额外遍历超过xs
而不是节省空间。)
编辑:我实际上并不打算将融合应用于实际的内存中Haskell列表,根据unzip
是否可以与其消费者融合,这种转换可能没有意义。我有一个设置,我知道unzip
可以融合(参见“FlumeJava:简单,高效的数据并行管道”)。
答案 0 :(得分:4)
也不是全自动的,但你可以给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。
答案 1 :(得分:3)
我设法找到两个资源,提到融合(un-)zip函数,至少是短暂的:
约瑟夫·斯文宁森。 “用于累积参数和类似Zip的功能的快捷方式融合” http://www.cse.chalmers.se/~josefs/publications/fusion.pdf 邓肯Coutts。 “Stream Fusion:用于同源序列类型的实用快捷方式融合” https://community.haskell.org/~duncan/thesis.pdf两种资源都没有明确提到这种“兄弟融合”。