管道还是不管道?

Chi*_*ils 4 f#

那是(某种程度上)这个问题.

我最近正在努力学习F#,而且我的资源似乎更倾向于在不清楚存在利益的地方使用管道.例如,给定一个curried形式的函数:

f: a -> b -> c -> R

我可以通过提供所有内联或管道参数来调用它c:

let r = f a b c 
let r = c |> f a b
Run Code Online (Sandbox Code Playgroud)

但是,是否存在成本或收益,还是纯粹的风格偏好?

AMi*_*res 8

应该没有成本.

UPDATE

可能是一些额外的费用.有时会插入一个额外的调用,但有时候编译器可以优化它以避免额外的调用.

我测试了以下代码:

let concat (a:string) (b:string) = System.String.Concat(a, b)

let f1 g a c = g a c
let f2 g a c = c |> g a

f1     concat "b" "c" \\ 00:00:33.8895616
f2     concat "b" "c" \\ 00:00:34.6051700
       concat "b" "c" \\ 00:00:35.0669532
"c" |> concat "b"     \\ 00:00:35.1948296
f1     (+)    "b" "c" \\ 00:00:35.4796687
f2     (+)    "b" "c" \\ 00:00:49.3227193
       (+)    "b" "c" \\ 00:00:35.0689207
"c" |> (+)    "b"     \\ 00:00:35.8214733
Run Code Online (Sandbox Code Playgroud)

对于每个案例,我执行了十亿次调用(1_000_000_000),那些是时间.正如您所看到的,只有呼叫f2 (+) "b" "c"比其他呼叫慢,这可能与(+)是使用SRTP的运营商有关.

感谢@PhillipCarter澄清.


管道的使用有助于类型推断:

let words = "many words".Split ' '

let wordsU1 = words |> Array.map (fun w -> w.ToUpper())  // ok
wordsU1 |> Seq.iter (printfn "words are %A") 

let wordsU2 = Array.map (fun w -> w.ToUpper()) words     // type annotation needed: (w:string)
Seq.iter (printfn "words are %A") wordsU2
Run Code Online (Sandbox Code Playgroud)

这两个调用Array.map是等价的,但第二个调用抱怨它不知道类型w.这是因为F#类型的推理机制从左到右工作,第二种情况words是在lambda函数之后.

它在风格上也更好.上面的代码可以更好地表达如下:

"many words".Split ' '
|> Array.map (fun w -> w.ToUpper())
|> Seq.iter (printfn "words are %A")
Run Code Online (Sandbox Code Playgroud)

因此,管道可用于链接多个表达式,而无需使用括号或将其绑定到名称.

  • 实际上有一个非零成本,但在大多数情况下它并不重要.@ ChiefTwoPencils的问题中的管道选项将引入一个`callvirt`.你可以看到差异[这里](https://sharplab.io/#v2:DYLgZgzgNALiCWwoBMQGoA+B7ADgUwDsACAZQE8IY8BbAWAChqtkBXYPIgWSIF4GiBRdjCJgiAcyIBDIgCMiAY14Tpcxf0HDRAchUz5SnoqIYAfHrlA=). (3认同)
  • 这取决于.如果可以的话,编译器将在一个最多有5个curried参数直接传递的调用上使用`InvokeFast`.这导致发射较少的IL并且稍微快一些.它已存在[至少5年](https://github.com/Microsoft/visualfsharp/blame/44c7e10ca432d8f245a6d8f8e0ec19ca8c72edaf/src/fsharp/FSharp.Core/prim-types.fsi#L1538).但是如果涉及单个参数,或者使用currying,那么它就不适用.您可以在我之前的评论中看到我给出的链接的差异. (2认同)