Pipelines and Composition
Pipelines also help type inference: writing the data first (xs |> List.map (fun x -> x.Length)) lets the compiler know x's type.
// |> forward pipe: x |> f == f x
let result =
[1 .. 10]
|> List.filter (fun x -> x % 2 = 0)
|> List.map (fun x -> x * x)
|> List.sum // 220
// <| backward pipe: f <| x == f x (avoids parentheses)
printfn "%d" <| List.sum [1; 2; 3]
// ||> and |||> pipe tuples into multi-argument functions
(3, 4) ||> max // 4
(1, 2, 3) |||> (fun a b c -> a + b + c) // 6
// >> forward composition: (f >> g) x == g (f x)
let increment x = x + 1
let double x = x * 2
let incThenDouble = increment >> double
incThenDouble 5 // 12
let doubleThenInc = increment << double // backward composition
doubleThenInc 5 // 11
// Point-free pipelines
let countWords: string -> int = fun s -> s.Split(' ', System.StringSplitOptions.RemoveEmptyEntries).Length
let sumOfSquaresOfEvens = List.filter (fun x -> x % 2 = 0) >> List.map (fun x -> x * x) >> List.sum
sumOfSquaresOfEvens [1 .. 10] // 220