Pipes
The pipe operator |> chains transformations left-to-right, making data flow readable.
Basic Pipes
Section titled “Basic Pipes”// Pipe the left side as the first argument to the right sideconst result = "hello" |> toUpperCase// Compiles to: toUpperCase("hello")Chaining
Section titled “Chaining”const result = users |> filter(.active) |> map(.name) |> sort |> join(", ")Compiles to:
const result = join(sort(map(filter(users, (u) => u.active), (u) => u.name)), ", ");The piped version reads like a recipe: take users, filter, map, sort, join.
Placeholder _
Section titled “Placeholder _”When the piped value isn’t the first argument, use _:
const result = 5 |> add(3, _)// Compiles to: add(3, 5)const result = value |> multiply(2) |> add(10, _) |> toStringDot Shorthand
Section titled “Dot Shorthand”For simple field access or comparisons, use .field:
todos |> Array.filter(.done == false)todos |> Array.map(.text)users |> Array.sortBy(.name).field creates an implicit closure. .done == false is shorthand for fn(t) t.done == false.
For anything more complex, use fn(x):
todos |> Array.map(fn(t) Todo(..t, done: !t.done))Method-Style Pipes
Section titled “Method-Style Pipes”Pipes work with any function, including methods accessed via imports:
import trusted { map, filter, reduce } from "ramda"
const total = orders |> filter(.status == "complete") |> map(.amount) |> reduce(fn(sum, n) sum + n, 0, _)Debugging with tap
Section titled “Debugging with tap”Need to inspect a value mid-pipeline without breaking the chain? Use tap:
const result = users |> Array.filter(.active) |> tap(Console.log) // logs filtered users, passes them through |> Array.map(.name) |> Array.sorttap calls the function you give it (for side effects like logging), then returns the original value unchanged. It compiles to an IIFE that calls the function and returns the value.
Pipe into Match
Section titled “Pipe into Match”You can pipe a value directly into match to combine pipelines with pattern matching:
const label = price |> match { _ when _ < 10 -> "cheap", _ when _ < 100 -> "moderate", _ -> "expensive",}This is equivalent to match price { ... } but lets you keep the pipeline flowing:
const message = response.status |> match { 200..299 -> "success", 404 -> "not found", 500..599 -> "server error", s -> `unexpected: ${s}`, }It works at the end of a chain too:
const label = product |> effectivePrice |> match { _ when _ < 10 -> "cheap", _ when _ < 100 -> "moderate", _ -> "expensive", }x |> match { ... } compiles identically to match x { ... }. It is pure syntax sugar for pipeline ergonomics.
When to Use Pipes
Section titled “When to Use Pipes”Pipes shine when you have a sequence of transformations. They replace:
| Instead of | Use |
|---|---|
c(b(a(x))) | x |> a |> b |> c |
x.map(...).filter(...).reduce(...) | x |> map(...) |> filter(...) |> reduce(...) |
| Temporary variables | Direct piping |
Operators
Section titled “Operators”Floe has three arrow-like operators:
fn(x) anonymous closures fn(a) a + 1-> match arms / types Ok(x) -> x, fn(string) -> number|> pipe data data |> transformEach has a distinct purpose. No ambiguity.