1

函数类型 A -> B 在某种意义上不是很好。尽管函数是一流的值,但由于效率问题,人们往往不能自由地操作它们。你不能应用太多的转换 (A -> B) -> (C -> D),在某些时候你必须计算一个值。

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

处理 Double -> Double 类型的函数有很多众所周知的技巧。可以将它们表示为给定特定基础的向量,该基础可以由三角函数、多项式等组成。

是否有任何通用技巧来解决 A -> B 类型的低效率问题?

或替代 -> ?

4

4 回答 4

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

流融合:什么是 Haskell 的流融合

于 2011-11-23T19:50:46.423 回答
3

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

于 2011-11-24T10:05:44.673 回答
2

最通用的技巧之一是记忆化——在计算后存储函数的值。链接:HaskellwikiSO 示例MemoCombinators。正如你所提到的,另一个技巧是当你有一个很好的函数类型(多项式、向量、泰勒级数等)时——它可以表示为一个列表、表达式等。

于 2011-11-23T19:23:55.790 回答
1

FWIW:在 Felix 中,这是一个严重依赖内联来提高性能的整个程序分析器,函数参数有三种:急切的、惰性的或“让编译器决定”。

在评估函数体之前,先评估急切的参数并将其分配给变量。

惰性参数是通过用参数表达式替换参数来评估的,无论它出现在哪里。

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

通常在 Felix 中,惰性求值更快:请注意,这并不意味着闭包。这意味着内联。然而,有时编译器会选择急切评估,它减少了代码膨胀,并且过多的内联会适得其反。我没有声称该算法有任何好处.. 但是 Felix 有时可以胜过 C 和 Ocaml(GHC 没有进入决赛)。

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

在我看来,如果你摒弃单独编译的陈旧概念,Haskell 会好很多:整个程序分析器可以做更多事情,而且文本比目标代码处理起来要快得多(考虑到缓存编译的完全自由结果)。让惰性语言使用为热切评估而设计的编译模型真是太疯狂了!

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

于 2011-12-17T10:11:40.480 回答