Haskell 如何在同一列表上融合两个地图?

Haskell 如何在同一列表上融合两个地图?,haskell,fusion,Haskell,Fusion,我们可以在表达式中的列表xs上融合两次遍历 (map f xs, map g xs) 像这样 unzip (map (\x -> (f x, g x)) xs) 有没有关于自动执行这种融合的研究 (如果返回的列表中的一个在另一个之前被使用,那么这里就有可能产生空间泄漏。我更感兴趣的是防止对xs进行额外的遍历,而不是节省空间。) 编辑:我实际上不想将融合应用于实际的内存中Haskell列表,在这些列表中,这种转换可能没有意义,这取决于解压是否可以与其使用者融合。我有一个设置,我知道unz

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

(map f xs, map g xs)
像这样

unzip (map (\x -> (f x, g x)) xs)
有没有关于自动执行这种融合的研究


(如果返回的列表中的一个在另一个之前被使用,那么这里就有可能产生空间泄漏。我更感兴趣的是防止对
xs
进行额外的遍历,而不是节省空间。)


编辑:我实际上不想将融合应用于实际的内存中Haskell列表,在这些列表中,这种转换可能没有意义,这取决于
解压
是否可以与其使用者融合。我有一个设置,我知道
unzip
可以融合(请参阅“FlumeJava:easy,efficient data parallel pipelines”)。

也不是完全自动的,但您可以给GHC一个类似的重写规则列表。见和。然后编译器在编译时使用这些规则优化程序。(请注意,编译器不会以任何方式检查规则是否有意义。)

编辑:要给出此特定问题的示例,我们可以写:

{-# 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
详细显示每个规则应用程序-请参阅。

我找到了两个参考资料,其中至少简要地提到了fusion(un-)zip类函数:

约瑟夫·斯文宁森。“用于累积参数和类Zip函数的快捷方式融合”

邓肯·库茨。“流融合:共导序列类型的实用快捷融合”


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

不是自动的,但无论如何都很好:除非这种融合的结果与其他东西融合,否则创建对和解压缩它们的开销将大于额外遍历的成本。@如果遍历是在一个大文件上,则不可能!我不打算将此应用于实际列表。解压将遍历与地图长度相同的列表,因此您不会保存遍历。现在,如果你关心的是节省融合给你的空间,那么它可以带来巨大的不同。我从你的评论中推断出你对太空不感兴趣,但我知道这与你说的不完全一样“防止对xs的额外遍历”也可以由大多数迭代器风格的包来完成。可能很有趣。我不认为我们可以写一个规则来匹配这些表达式。GHC规则必须以函数名开头。