Dive C1.04.1
The pipe operator
Forward application: x |> f is exactly f x, with the value already in hand.
The pipe |> is the most-used operator in idiomatic F#, and it does
one small thing: it applies a function to a value, written the other way round. By definition
let (|>) x f = f x, so x |> f and
f x compute the same value. The point is not the saved keystroke — it is
reading order. 5 |> double |> inc reads left to right as "5,
doubled, incremented", in the order the steps actually run; the nested-call form
inc (double 5) reads inside-out, from the middle. This dive defines the pipe, steps a
value through a chain, and adds the backward pipe <|.
One line of definition
The pipe is not a compiler keyword; it is an ordinary operator defined in FSharp.Core.
Its whole definition is one line, and it explains the behaviour completely: the operator takes a value
x on the left and a function f on the right, and returns
f x.
// from FSharp.Core — the whole definition let (|>) x f = f x let double x = x * 2 // val double : int -> int let inc x = x + 1 // val inc : int -> int 5 |> double // val it : int = 10 == double 5 5 |> double |> inc // val it : int = 11 == inc (double 5)
The pipe associates to the left, so a chain reduces from the left:
5 |> double |> inc is (5 |> double) |> inc. The
left part runs first and produces 10; that result is then piped into
inc. The reading order on the page matches the evaluation order in the machine.
- |>
- forward application:
x |> f = f x. The value is on the left, the function on the right. - reading order
5 |> double |> increads as the steps run;inc (double 5)reads inside-out.- associativity
- the pipe is left-associative: a chain reduces left to right, each result feeding the next stage.
- same value
- the pipe changes the spelling, never the result:
5 |> doubleanddouble 5both give10.
Inside-out, then left to right
Take the chain 5 |> double |> inc and its nested-call twin
inc (double 5). They produce the same 11, but a reader walks
them in opposite directions. The diagram lays the two forms over the same three tokens — the input, the two
functions — so the difference is only the path the eye takes.
5 |> double |> inc · the same result, read two ways
The pipe and the nested call compute the same value. The pipe earns its place by reading in the order the work happens, not from the middle out.
Step 5 |> double |> inc |> square
Walk the value through a fixed three-function chain. The input is 5; the chain is
double (x*2), then inc
(x+1), then square (x*x). Each step
lights the stage about to run and shows the equivalent f x rewrite. The running value
is 5 → 10 → 11 → 121.
5 |> double |> inc |> square · one stage at a time
- 5 |> double double 5 = 10
- 10 |> inc inc 10 = 11
- 11 |> square square 11 = 121
- 121 the value
Three functions, one value, four readings of the same number. The pipe is the chain; each stage
is one f x.
The backward pipe <|
The pipe has a mirror image. The backward pipe <| applies the function on the
left to the value on the right: f <| x = f x. It does not reverse the data flow —
it keeps the function first, the value last — and its everyday use is to drop a pair of
parentheses on the right-hand argument.
// from FSharp.Core let (<|) f x = f x printfn "%d" (1 + 2) // prints 3 printfn "%d" <| 1 + 2 // prints 3 — no parentheses needed
Both lines print 3. The backward pipe has lower precedence than
+, so 1 + 2 is computed first and the result handed to
printfn "%d". The forward pipe is the one a program leans on; the backward pipe is a
smaller tool, kept for the cases where it reads more cleanly than a bracket.
Forward application
Apply a function to a value, written so the value comes first and the steps read in order.
F# today
x |> f threads the value; f <| x drops the brackets. Both are f x.
Where this leads
The pipe needs a value now — it threads what you already hold. The next dive asks the other
question: what if there is no value yet, only functions to wire together for later? That is
composition >>, which glues two functions into one new function
and names no argument at all.
References
Sources
- Microsoft — F# documentation — the pipe-forward operator and function-application syntax.
- FSharp.Core API reference —
(|>)and(<|)in theOperatorsmodule. - The F# Language Specification — operator definitions, precedence, and left-associativity of the pipe.
Related in this course
- C1.04.2 — Function composition — gluing functions for later, the next step from the pipe.
- C1.03 — Functions — the functions the pipe threads a value through.
- Elixir — Composition — the same forward pipe on the BEAM.