Skip to content

pipe and flow ​

ts
import { pipe, flow } from 'smullyan/pipe';

Both apply functions left to right. pipe starts from a value; flow builds a function.

ts
pipe(41, inc, show); // '42'
flow(inc, show)(41); // '42'

The difference ​

flow's first function may take any number of arguments — everything after it is unary, because it receives the previous result:

ts
const add = (a: number, b: number): number => a + b;
flow(add, show)(40, 2); // '42'

pipe always begins with exactly one value, so its functions are all unary.

Arity and inference ​

Both carry hand-written overload chains supporting twenty functions, with exact inference at every step:

ts
pipe(1, inc, dbl, inc, dbl, show, len); // number, inferred precisely

Beyond twenty, nest a second pipe.

Why overloads here and nowhere else

Combinators are curried and single-signature precisely to avoid overload resolution widening generics to unknown — see Currying.

pipe and flow are variadic by nature, so there is no single signature to write. Variadic tuple types can express the chain, but inference through them degrades badly: intermediate positions widen and errors become unreadable. The chains are generated mechanically rather than transcribed by hand.

Relationship to the birds ​

pipe and flow are the Thrush and the Queer bird iterated, which the law suite asserts directly:

ts
pipe(x, f, g) === B(g)(f)(x); // Bluebird, right to left
pipe(x, f, g) === Q(f)(g)(x); // Queer bird, left to right
flow(f, g)(x) === pipe(x, f, g);

For a single function, pipe(x, f) is exactly the Thrush: T(x)(f).

With the ADTs ​

Because every ADT combinator is data-last, they drop straight in:

ts
import * as Option from 'smullyan/option';

pipe(
  Option.fromNullable(process.env.PORT),
  Option.map(Number),
  Option.filter((n: number) => Number.isInteger(n)),
  Option.getOrElse(() => 3000),
);

This is the reason for the data-last convention: the value being transformed arrives last, so partial application produces exactly the unary functions pipe wants.

MIT licensed.