我正在学习使用F#进行功能编程的第一步 - 我刚刚遇到了Forward Pipe(|>)和Forward Composition(>>)运算符。起初我以为它们只是糖而不是对最终运行的代码产生影响(虽然我知道管道有助于类型推断)。
但是我遇到了这篇SO文章: What are advantages and disadvantages of “point free” style in functional programming? 其中有两个有趣且信息丰富的答案(而不是为我简化的事情,开启了围绕“无点”或“无意义”风格的整套蠕虫)我从这些(和其他阅读)带回家是无点的是一个争论的领域。与lambas一样,无点样式可以使代码更容易理解,或者更难以根据用途使用。它可以帮助有意义地命名。
但我的问题涉及对第一个答案的评论: AshleyF回答道:
“在我看来,组合可能会降低GC压力,使编译器更明显的是不需要像流水线那样产生中间值;帮助使所谓的“砍伐森林”问题更容易处理。“
Gasche回复:
“关于改进编译的部分根本不是真的。在大多数语言中,无点样式实际上会降低性能。 Haskell在很大程度上依赖于优化,因为它是使这些东西的成本可以承受的唯一方法。充其量,那些组合器被内联,你得到一个相同的有点版本“
任何人都可以扩展性能影响吗? (一般而言,特别是对于F#)我只是假设它是一种写作风格的东西,编译器会将这两种习语解析成等价的代码。
答案 0 :(得分:35)
这个答案将是F#特定的。我不知道其他函数式语言的内部是如何工作的,以及它们不能编译成CIL的事实可能会产生很大的不同。
我在这里可以看到三个问题:
|>
?>>
?答案(使用the question you linked to中的示例):
x |> sqr |> sum
和sum (sqr x)
之间有什么区别吗?
不,没有。编译的CIL完全相同(这里用C#表示):
sum.Invoke(sqr.Invoke(x))
(Invoke()
被使用,因为sqr
和sum
不是CIL方法,它们是FSharpFunc
,但这里不相关。)
(sqr >> sum) x
和sum (sqr x)
之间有什么区别吗?
不,两个样本都编译成与上面相同的CIL。
let sumsqr = sqr >> sum
和let sumsqr x = (sqr >> sum) x
之间有什么区别吗?
是的,编译的代码是不同的。如果指定参数,则sumsqr
将编译为常规CLI方法。但是如果你没有指定它,它会被编译为类型为FSharpFunc
的属性,并带有一个支持字段,其Invoke()
方法包含代码。
但是all的效果是调用无点版本意味着加载一个字段(FSharpFunc
),如果指定参数,则不会这样做。但我认为除非在最极端的情况下,否则不应该对性能产生明显的影响。