ESC
Type to search...
S
Soli Docs

Pipeline Operator

Chain function calls in a readable, left-to-right manner with the pipeline operator.

Basic Usage

|> Pipeline Operator

Passes the left-hand value as the first argument to the right-hand function.

def double(x: Int) -> Int { x * 2 }
def add_one(x: Int) -> Int { x + 1 }
def square(x: Int) -> Int { x * x }

# Without pipeline (nested calls)
result1 = square(add_one(double(5)))  # Hard to read

# With pipeline (left to right)
result2 = 5 |> double() |> add_one() |> square()
print(result2)  # ((5 * 2) + 1)^2 = 121

With Multiple Arguments

When the right-hand function takes more arguments, the piped value is inserted as the first argument.

def add(a: Int, b: Int) -> Int { a + b }
def multiply(a: Int, b: Int) -> Int { a * b }

# `5 |> add(3)` is shorthand for `add(5, 3)`
result = 5 |> add(3) |> multiply(2)  # (5 + 3) * 2 = 16
print(result)

# Inline lambdas via the immediately-invoked `|x| { ... }()` form
def subtract(a: Int, b: Int) -> Int { a - b }
def divide(a: Int, b: Int) -> Int { int(a / b) }

calc = 100
  |> |x| { subtract(x, 10) }()
  |> |x| { divide(x, 3) }()
  |> |x| { multiply(x, 4) }()
print(calc)  # ((100 - 10) / 3) * 4 = 120

With Collection Methods

Iteration over arrays uses method chaining: .map, .filter, .reduce, .each. Lambdas are most concise in pipe form — |x| x + 1 — but fn(x) x + 1 works too.

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# Method chaining with pipe lambdas
evens_squared = numbers
  .filter(|x| x % 2 == 0)
  .map(|x| x * x)
print(evens_squared)  # [4, 16, 36, 64, 100]

# Reduce with two parameters
sum_of_evens = numbers
  .filter(|x| x % 2 == 0)
  .reduce(|acc, x| acc + x, 0)
print(sum_of_evens)  # 30

# `.each` for side effects
numbers.filter(|x| x > 5).each(|x| print(x))

You can still use |> with these chains by pre-defining a callable, e.g. numbers |> |arr| arr.filter(|x| x > 5)().

Real-World Examples

Data & HTTP processing

# Data processing pipeline
def process_user_data(raw_data: Hash) -> Hash
  raw_data
    |> |d| { d["sanitized_email"] = d["email"].lower().trim(); d }()
    |> validate_user()
    |> enrich_profile()
    |> calculate_metrics()
end

# HTTP request pipeline
def fetch_and_process(url: String) -> Hash
  url
    |> HTTP.get_json()
    |> transform_response()
    |> validate_data()
    |> format_output()
end

Complex data pipeline

sales_data = [
  {"product": "A", "quantity": 10, "price": 100},
  {"product": "B", "quantity": 5,  "price": 200},
  {"product": "C", "quantity": 15, "price": 50},
]

total_revenue = sales_data
  .map(|sale| sale["quantity"] * sale["price"])
  .reduce(|acc, rev| acc + rev, 0)

print("Total Revenue: $" + str(total_revenue))  # $2750

Benefits of Pipeline

Readability

Data flows left-to-right, matching natural reading order.

Debugging

Easy to add intermediate steps or breakpoints.

Composability

Build complex transformations from simple functions.

No Nesting

Avoid deeply nested function calls.