优化连续的地图/过滤/折叠调用

时间:2016-03-14 09:08:01

标签: optimization functional-programming language-agnostic higher-order-functions

我们说我有一个很重要的列表,我想要执行多个地图,过滤和折叠/减少调用。为了清晰和表达,这应该通过传递给map / filter / fold的小lambda函数来完成。但是,据我所知,这些实际上每次遍历列表,在其上调用lambda(可能是内联的)并生成一个新列表。如果是这种情况,我可以编写for-each循环并将所有lambda合并到其正文中。

我测量了一个简单的map / filter / reduce算法的执行时间以及Python中每个循环的相应命令,后者的速度提高了两倍以上,就像我预期的那样,但我知道Python不是最好的语言在这方面。

我的问题是:编译器是否有可能找出这些并以某种方式将它们合并为一个循环?有没有编译器这样做?我主要对函数式语言(Haskell,Erlang / Elixir,Scala)感兴趣,但也很高兴听到其他语言(Rust' s实现,LINQ)。

1 个答案:

答案 0 :(得分:3)

是的,这种优化已被多次考虑过。

使用的一个术语或方法是"fusion"(也称为流或map fusion),其目标是以map f . map g = map (f . g)等模式智能地内联迭代转换。这主要是在编译器的帮助下完成的,但可以在这些函数的“正常”实现上工作(如果它们在某种程度上是智能的)。

另一种方法是通过累积所有中间闭包来手动执行这种内联,并且仅在实际需要值时应用组合变换(这与惰性求值密切相关,在某些语言中,如Haskell ,自动完成)。这些事情可以在Scala的viewsStream s,或Clojure的transducers中找到(尽管它们以更复杂的方式工作)。这些懒惰事物的问题在于它们更容易陷入太空问题(我听说过)。

Python中的迭代器(以及C#的IEnumerable / LINQ内容和Java的新Stream s)原理通过后一原理工作,涉及语言提供的迭代支持(涉及一些内部状态)。这就是xs = map(print, range(10))不会立即打印任何内容的原因,并且只能遍历一次;在迭代的每一步中,嵌套迭代器将相互询问下一个值,转换它并更新它们的状态。 (可能你所测量的差异更多地归因于这个涉及的机器而不是重复迭代。)