A pipeline is a left-to-right sequence of data transformations: each stage receives the previous stage’s output and produces the next value. This gives an application a simple shape—represent state as data, write functions that transform it, and compose those functions until reaching an effect such as returning JSON, writing a file, or sending an email. section 1.5.5
In F#, the forward-pipe operator, |>, makes that flow explicit. `value |> function` is equivalent to calling `function value`; for a curried function, the piped value supplies its last argument. Thus `10 |> add 5` means the same as `add 5 10`. A later stage can follow whenever its input type matches the preceding stage’s output type. section 6.1.3 section 6.4
Read transformations in execution order
Nested calls make the first transformation appear furthest right, while temporary variables manually carry each intermediate result. A pipeline keeps the data first and lists stages in the order they run: `10` `|> add 5` `|> add 7` `|> multiply 2` The multiline form is useful once stages have meaningful names or the chain grows beyond a single line. section 6.1.3
Follow the diagram as data moves through successive functions; the output arrow from one stage becomes the input to the next. section 6.1.3
Pipelines favor small, independently useful functions over a large routine that manages state between steps. For example, a customer identifier can flow through loading, review, email creation, and sending. Because stages need only agree on input and output shapes, a transformation can be inserted, replaced, or reused without requiring special pipeline declarations. section 6.1.3 section 7.6
Query a collection declaratively
A collection pipeline applies the same idea to a whole list. To find the team with the most away wins, filter match results, count them by away team, then choose the largest count: `results` `|> List.filter isAwayWin` `|> List.countBy (fun result -> result.AwayTeam)` `|> List.maxBy (fun (team, count) -> count)` Each stage returns a new result set rather than mutating a shared summary. This is shorter than nested loops and mutable bookkeeping, while making the requested transformations visible in order. section 7.2.1
Listing 7.3 A declarative query implementation
let isAwayWin result = result.AwayGoals > result.HomeGoals
let wonAwayTheMost =
results
|> List.filter isAwayWin #1
|> List.countBy (fun result -> result.AwayTeam) #2
|> List.maxBy (fun (team, count) -> count) #3
Inspect the three collection stages as a complete, concrete pipeline from match results to the winning away team. section 7.2.1
Long pipelines remain inspectable by running an initial subset in F# Interactive and observing its intermediate result. Editors can also show the inferred type at each stage, helping locate a broken connection when one function’s output cannot satisfy the next function’s input. Build and test a chain incrementally rather than treating it as one opaque expression. section 7.2.2
Use partial execution to see how a filter changes the data before continuing into later aggregation stages. section 7.2.2
The pattern extends beyond lists. It can process event streams, command input, files, database data, and transient domain data when they share a usable representation. In web work, the same functional style models an HTTP request/response pipeline, allowing composable F# handlers to run on ASP.NET Core. section 10.1.1 section 13.2















































