17

我在使用 F# 学习函数式编程方面迈出了第一步,我刚刚遇到了正向管道 (|>) 和正向组合 (>>) 运算符。起初我认为它们只是糖而不是对最终运行的代码产生影响(尽管我知道管道有助于类型推断)。

但是我遇到了这篇 SO 文章: 函数式编程中“无点”风格的优点和缺点是什么? 其中有两个有趣且内容丰富的答案(不是为我简化事情,而是打开了一整罐围绕“无意义”或“无意义”风格的蠕虫)我从这些(和其他阅读)中获得的收获是无意义的是一个有争议的领域。与lambas 一样,无点样式可以使代码更容易理解,或者更难理解,具体取决于使用情况。它可以帮助有意义地命名事物。

但我的问题涉及对第一个答案的评论:AshleyF 在答案中沉思:

“在我看来,组合可以通过让编译器更清楚地表明不需要像流水线一样产生中间值来降低 GC 压力;帮助使所谓的“森林砍伐”问题更容易解决。”

加舍 回复:

“关于改进编译的部分根本不是真的。在大多数语言中,无点风格实际上会降低性能。Haskell 严重依赖优化,正是因为它是使这些东西的成本可以承受的唯一方法。充其量,这些组合器被内联了,你得到一个等效的有意义的版本”</p>

任何人都可以扩展性能影响吗?(一般来说,特别是对于 F#)我刚刚假设它是一种写作风格的东西,编译器会将这两个习语解开成等效的代码。

4

1 回答 1

35

这个答案将是特定于 F# 的。我不知道其他函数式语言的内部是如何工作的,而且它们不编译为 CIL 的事实可能会产生很大的不同。

我可以在这里看到三个问题:

  1. 使用 对性能有何影响|>
  2. 使用 对性能有何影响>>
  3. 声明带有参数和不带参数的函数之间的性能差异是什么?

答案(使用您链接到的问题中的示例):

  1. x |> sqr |> sum和有什么区别sum (sqr x)吗?

    不,没有。编译后的 CIL 完全一样(这里用 C# 表示):

    sum.Invoke(sqr.Invoke(x))
    

    (Invoke()被使用,因为sqrandsum不是 CIL 方法,它们是FSharpFunc,但这与这里无关。)

  2. (sqr >> sum) x和有什么区别sum (sqr x)吗?

    不,两个示例都编译为与上述相同的 CIL。

  3. let sumsqr = sqr >> sum和有什么区别let sumsqr x = (sqr >> sum) x吗?

    是的,编译后的代码是不同的。如果指定参数,sumsqr则编译成普通的 CLI 方法。但是,如果您不指定它,它会被编译为FSharpFunc带有支持字段的类型属性,其Invoke()方法包含代码。

    但是所有的效果是调用无点版本意味着加载一个字段(the FSharpFunc),如果您指定参数,则不会这样做。但我认为这不应该显着影响性能,除非在最极端的情况下。

于 2012-07-25T14:06:09.610 回答