无点风格的性能影响

时间:2012-07-25 12:38:14

标签: performance f# functional-programming pointfree

我正在学习使用F#进行功能编程的第一步 - 我刚刚遇到了Forward Pipe(|>)和Forward Composition(>>)运算符。起初我以为它们只是糖而不是对最终运行的代码产生影响(虽然我知道管道有助于类型推断)。

但是我遇到了这篇SO文章: What are advantages and disadvantages of “point free” style in functional programming? 其中有两个有趣且信息丰富的答案(而不是为我简化的事情,开启了围绕“无点”或“无意义”风格的整套蠕虫)我从这些(和其他阅读)带回家是无点的是一个争论的领域。与lambas一样,无点样式可以使代码更容易理解,或者更难以根据用途使用。它可以帮助有意义地命名。

但我的问题涉及对第一个答案的评论: AshleyF回答道:

  

“在我看来,组合可能会降低GC压力,使编译器更明显的是不需要像流水线那样产生中间值;帮助使所谓的“砍伐森林”问题更容易处理。“

Gasche回复:

  

“关于改进编译的部分根本不是真的。在大多数语言中,无点样式实际上会降低性能。 Haskell在很大程度上依赖于优化,因为它是使这些东西的成本可以承受的唯一方法。充其量,那些组合器被内联,你得到一个相同的有点版本“

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

1 个答案:

答案 0 :(得分:35)

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

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

  1. 使用|>
  2. 的性能影响是什么?
  3. 使用>>
  4. 的性能影响是什么?
  5. 使用参数声明函数和不使用它们之间的性能差异是什么?
  6. 答案(使用the question you linked to中的示例):

    1. x |> sqr |> sumsum (sqr x)之间有什么区别吗?

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

      sum.Invoke(sqr.Invoke(x))
      

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

    2. (sqr >> sum) xsum (sqr x)之间有什么区别吗?

      不,两个样本都编译成与上面相同的CIL。

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

      是的,编译的代码是不同的。如果指定参数,则sumsqr将编译为常规CLI方法。但是如果你没有指定它,它会被编译为类型为FSharpFunc的属性,并带有一个支持字段,其Invoke()方法包含代码。

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