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