jonnifyfsharp

Dive C1.04.2

Function composition

Glue two functions into one — double >> inc is a single function, no value in sight.

Where the pipe threads a value you already hold, composition >> builds a new function out of two existing ones, to use later. By definition let (>>) f g x = g (f x), so f >> g is the function fun x -> g (f x): run f first, hand its output to g. It runs left first — double >> inc doubles, then increments. The payoff is point-free definitions: name the combined function and never mention its argument. This dive defines >>, contrasts it with the pipe, and adds the backward composition <<.

C1.04.2 · part 1

One function out of two

Composition is another ordinary operator from FSharp.Core, defined in one line. It takes two functions f and g and returns a function that applies f first and feeds the result to g. The result is a value of function type — bind it to a name and it is usable on its own.

// from FSharp.Core — the whole definition
let (>>) f g x = g (f x)

let double x = x * 2          // val double : int -> int
let inc x = x + 1             // val inc : int -> int

let f = double >> inc        // val f : (int -> int)   — double then inc
f 5                          // val it : int = 11

let g = inc >> double        // inc then double
g 5                          // val it : int = 12      ==  double (inc 5)

The order matters: f and g use the same two functions but in opposite order, and they give 11 and 12. double >> inc applied to 5 is inc (double 5) = inc 10 = 11; inc >> double is double (inc 5) = double 6 = 12. The left function in the >> always runs first.

>>
composition: (f >> g) is fun x -> g (f x). The left function runs first.
(int -> int)
double >> inc is a value of function type; the F# Interactive prints it in parentheses.
order
double >> inc doubles then increments; inc >> double reverses it.
point-free
the definition let f = double >> inc names the combined function and mentions no argument.

Thread a value, or fuse the functions

The pipe and composition reach the same 11 by different routes. Switch between the two views: the pipe view threads the value 5 through double then inc; the compose view fuses the two boxes into one function f = double >> inc and applies it to 5. The pipe needs the value present; composition builds the function first.

double then inc · two ways to the same 11

View A · pipe threads the value

5 double 10 |> inc 11

View B · compose fuses the functions

double >> inc f = double >> inc f 5 11
pipe · 5 |> double |> inc threads the value 5 through each function · result 11

Same two functions, same 11. The pipe runs the steps on a value in hand; composition packages the steps into one function for whenever a value arrives.

The pipe

Needs a value now: 5 |> double |> inc threads what you already hold.

Composition

Builds a function for later: double >> inc names no value at all.

C1.04.2 · part 2

The backward composition <<

Composition has a reverse, <<, which runs the right function first: (g << f) is fun x -> g (f x). It reads the way the nested-call form reads, with the outermost function written first. So inc << double is the same function as double >> inc — double first, then increment.

// from FSharp.Core
let (<<) g f x = g (f x)

let h = inc << double        // val h : (int -> int)   — double first, then inc
h 5                          // val it : int = 11   ==  (double >> inc) 5

The forward composition >> matches the left-to-right reading of the pipe and is the one F# code uses most. The backward << reads like mathematics, where g ∘ f means "apply f, then g". Both define the same kind of function; the choice is which reading order suits the line.

Where this leads

A composition of two functions is a function; a composition of many is still one function. The next dive puts both operators to work on real data: a pipeline that chains the collection functions with |>, and the same pipeline named point-free with >>. That is the shape every later module reuses.

References

Sources

Related in this course