这是(某种)问题。
我最近尝试学习F#,而我的资源似乎更喜欢在尚无好处的地方使用管道。例如,给定一个函数形式的函数:
f: a -> b -> c -> R
我可以通过以下方式调用它:以内联或管道c
的形式提供所有参数,
let r = f a b c
let r = c |> f a b
但是有成本或收益,还是纯粹是风格上的偏爱?
答案 0 :(得分:8)
应该没有费用。
更新
可能会一些额外费用。 有时会插入一个额外的调用,但有时编译器可以优化它以避免额外的调用。
我测试了以下代码:
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
对于每种情况,我都进行了十亿次呼叫(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
对Array.map
的两个调用是等效的,但是第二个调用则抱怨它不知道w
的类型。这是因为F#类型推断机制从左到右起作用,在第二种情况下,words
在lambda函数之后。
从样式上也更好。上面的代码可以这样更好地表达:
"many words".Split ' '
|> Array.map (fun w -> w.ToUpper())
|> Seq.iter (printfn "words are %A")
因此,可以使用管道将多个表达式链接起来,而不必使用括号或将其绑定到名称。
答案 1 :(得分:0)
管道。 Don Syme喜欢管道(proof):)
还请记住,还有||>
和|||>
管道。