I was reading this article by Tomas Petricek, and it mentioned the pipelining |>
as in the example given:
> 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];;
What does pipelining mean? Initially, I thought it was akin to a CPU instruction being pipelined within the cores. Can you explain what it is and how does it work in the context of F#?
Thanks, Best regards, Tom.
In some ways there's nothing special about pipelining; instead of writing f (g (h x))
, you can write x |> h |> g |> f
, which doesn't seem like an obvious improvement. However, there are two points worth keeping in mind:
x |> Array.map (fun s -> s.Length)
will work when x is a string[]
, but Array.map (fun s -> s.Length) x
won't; you need to do Array.map (fun (s:string) -> s.Length) x
instead.Pipelining means passing the results of one function to another function. In the example you give "nums" is passed the List.Filter, the filtered results are then passed to List.Map.
More info here: http://msdn.microsoft.com/en-us/magazine/cc164244.aspx#S6
As others mentioned, pipelining is more like a UNIX shell pipeline. It let's you write some input followed by operations that should be applied to it, instead of usual nested function calls. In this example, the standard F# code would look like this:
let r = List.map (add 10) (List.filter (fun n-> n%2 <> 0) nums)
Note that the input nums
is deeply nested in the expression and it isn't easy to see that it is first filtered and then projected. Using pipelining, you can write the code differently, but it will mean exactly the same thing.
The trick is that pipelining operator takes two parameters using infix notation (e.g. x |> f
). The x
parameter will be passed as the last argument to a function on the right (f
). You can use pipelining with any F# functions:
let sinOne = 1.0 |> sin
let add a b = a + b
let r = 10 |> add 5 // it doesn't always make code more readable :-)
An important point about F# pipelining operator is that it isn't any special built-in feature of the language. It is a simple custom operator that you can define on your own:
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With