有效的功能表示

时间:2011-11-23 17:26:47

标签: performance function haskell language-theory

功能类型A - > B在某种意义上不是很好。虽然功能是一等值,但由于效率问题,通常无法自由操作它们。你不能应用太多的转换(A - > B) - > (C - > D),在某些时候你必须计算一个值。

显然这是由于 - >的非严格性质。

有很多熟悉的技巧来处理Double类型的函数 - >双。可以将它们表示为给定某个基础的向量,其可以包括trig函数,多项式等。

是否有任何一般技巧可以解决A的无效率问题? B型?

或替代 - > ?

4 个答案:

答案 0 :(得分:5)

您的关注似乎是h === f • gf • g通常效率低于h。给定编译时已知的函数组合,编译器执行两个技巧,可以使f • g比您怀疑的更有效 - 内联和融合。内联避免了第二个函数调用的额外间接,并为优化开辟了许多新的机会。流融合(或构建/折叠融合)可以(给出基本示例)将诸如map f . map g的组合转变为map (f . g),从而通过常数因子减少结构的遍历次数。 Fusion不仅在列表上运行,还在其他结构上运行,并提供了Haskell库(如Vector)高效性能的一个原因。

捷径融合:http://www.haskell.org/haskellwiki/Correctness_of_short_cut_fusion

流融合:What is Haskell's Stream Fusion

答案 1 :(得分:3)

我无法证实这一点。作为AFRP的高效用户和实现者,我正在对完全多态函数进行大量转换,深度嵌套以及长时间运行的应用程序。请注意,Haskell编译器不使用传统的基于堆栈的函数调用范例。他们使用图缩减算法。我们没有与C相同的问题。

答案 2 :(得分:2)

最常见的技巧之一是memoization - 在计算函数后存储函数的值。链接:HaskellwikiSO exampleMemoCombinators。正如你所提到的,另一个技巧是你有一个很好的函数类型(多项式,向量,泰勒级数等) - 然后它可以表示为列表,表达式等。

答案 3 :(得分:1)

FWIW:在Felix中,整个程序分析器严重依赖内联性能,函数参数有三种:渴望,懒惰或“让编译器决定”。

在评估函数体之前,评估Eager参数并将其赋值给变量。

通过将参数替换为参数表达式来计算延迟参数。

默认为“让编译器决定”。对于大量的“普通”代码(无论这意味着什么),无论您是使用急切还是懒惰的评估,它都没有任何区别。

通常在Felix懒惰评估中更快:请注意这并不意味着关闭。这意味着内联。但是,有时编译器会选择急切的评估,它会减少代码膨胀,过多的内联会产生反作用。我没有声称算法有任何好处..但是Felix有时可以胜过C和Ocaml(GHC没有进入决赛)。

作为一个简单的例子..类型类。 Felix有类型类,有点像Haskell。没有或只有很少的性能开销..当然没有词典!

在我看来,如果你只是抛弃了单独编译的古老概念,那么Haskell会好得多:整个程序分析器可以做得更多,文本比目标代码更快地工作(给定完全自由)缓存编译结果)。让懒惰的语言使用为急切评估而设计的编译模型真是太疯狂了!

Haskell变体可能尝试的另一件事是放弃所有函数都是懒惰的想法,而是采用评估策略无关的想法,除非另有说明。这可能会带来更多优化机会。