我正在阅读Tomas Petricek的这篇文章,它提到了流水线|>
,如给出的例子:
> let nums = [1; 2; 3; 4; 5];; val nums : list<int> > let odds_plus_ten = nums |> List.filter (fun n-> n%2 <> 0) |> List.map (add 10) val odds_plus_ten : list<int> = [11; 13; 15];;
流水线是什么意思?最初,我认为它类似于在内核中流水线化的CPU指令。你能解释它是什么以及它如何在F#的背景下起作用?
谢谢, 最好的祝福, 汤姆。
答案 0 :(得分:14)
在某些方面,流水线没有什么特别之处;而不是写f (g (h x))
,你可以写x |> h |> g |> f
,这似乎不是一个明显的改进。但是,有两点值得记住:
x |> Array.map (fun s -> s.Length)
将在x为string[]
时有效,但Array.map (fun s -> s.Length) x
则不会;你需要改为Array.map (fun (s:string) -> s.Length) x
。答案 1 :(得分:11)
Pipelining意味着将一个函数的结果传递给另一个函数。在示例中,您将“nums”传递给List.Filter,然后将过滤后的结果传递给List.Map。
此处有更多信息:http://msdn.microsoft.com/en-us/magazine/cc164244.aspx#S6
答案 2 :(得分:3)
正如其他人所提到的,流水线操作更像是UNIX shell管道。它让你编写一些输入,然后是应该应用于它的操作,而不是通常的嵌套函数调用。在此示例中,标准F#代码如下所示:
let r = List.map (add 10) (List.filter (fun n-> n%2 <> 0) nums)
请注意,输入nums
深深嵌套在表达式中,并且不容易看到它首先被过滤然后进行投影。使用流水线技术,你可以用不同的方式编写代码,但它的意思完全相同。
技巧是流水线操作符使用中缀表示法(例如x |> f
)获取两个参数。 x
参数将作为最后一个参数传递给右侧的函数(f
)。您可以在任何F#函数中使用流水线操作:
let sinOne = 1.0 |> sin
let add a b = a + b
let r = 10 |> add 5 // it doesn't always make code more readable :-)
关于F#流水线操作符的一个重点是它不是该语言的任何特殊内置功能。它是一个简单的自定义运算符,您可以自己定义:
let (|>) x f = f x
// Thanks to operator associativity rules, the following:
let r = 1.0 |> sin |> sqrt
// ...means this:
let r = (1.0 |> sin) |> sqrt
答案 3 :(得分:2)