The hardest tokens to save are the names you invent to thread values between steps.
The binding chain problem
A three-stage data transform in ilo without pipe:
a=flt pos xs
b=map dbl a
map sq b
Thirteen tokens. Two of them - a, b - exist purely as connective tissue. They name intermediate states that nobody cares about. An AI agent generating this code has to invent those names, keep track of them, and use the right one in the next line.
The >> operator
>> passes the result of the left side as the last argument to the right side:
xs >> flt pos >> map dbl >> map sq
Ten tokens. No invented names. Left to right, each stage receives the output of the previous one.
Same mental model as Unix pipes:
cat file | grep foo | sort | uniq
Or Elixir’s |>. The value flows through and you describe the transformation directly.
The saving compounds
| Chain length | Binding chain | Pipe | Tokens saved |
|---|---|---|---|
| 2 stages | 8 tokens | 7 tokens | 1 |
| 3 stages | 13 tokens | 10 tokens | 3 |
| 5 stages | 23 tokens | 16 tokens | 7 |
Each additional stage adds one invented name that appears twice - once on the left of =, once as an argument to the next call. Pipe eliminates both. The longer the chain, the bigger the win.
How it works
>> desugars at parse time. The left side becomes the last argument of the right side call:
xs >> flt pos >> map dbl
-- desugars to:
map dbl (flt pos xs)
No new runtime mechanism. No new AST node. It also composes with ! for auto-unwrap:
url >> get! >> jpar! -- fetch URL, parse JSON, propagate errors automatically
Binding when you need it
Sometimes you want to name an intermediate result - to use it multiple times, or to make the code clearer:
clean=xs >> flt pos >> map dbl
len clean
>> produces a value like any other expression. You can bind it, pass it, or return it.