Thirty-six combinators
The whole forest, from the Bluebird to the Sage. Each exported under its symbol, its bird name, and its familiar FP name — B, bluebird and compose are the same function.
The bird combinators of To Mock a Mockingbird, plus Option, Result, Task and Reader — curried, tree-shakable, and zero-dependency.
import { B, C, K, S, Y } from 'smullyan/birds';
import { pipe } from 'smullyan/pipe';
import * as Option from 'smullyan/option';
// Composition — the Bluebird
const incThenShow = B(String)((n: number) => n + 1);
incThenShow(41); // '42'
// Recursion without a name — the Sage bird
const factorial = Y<number, number>((rec) => (n) => (n <= 1 ? 1 : n * rec(n - 1)));
factorial(5); // 120
// Pipelines
pipe(
Option.fromNullable(process.env.PORT),
Option.map(Number),
Option.filter((n: number) => Number.isInteger(n)),
Option.getOrElse(() => 3000),
);pnpm add smullyannpm install smullyanbun add smullyanEvery module is side-effect free and independently importable, so you ship only what you use.
| Import | Contains |
|---|---|
smullyan | The birds, plus pipe and flow |
smullyan/birds | All thirty-six combinators |
smullyan/pipe | pipe and flow |
smullyan/option | Option<A> |
smullyan/result | Result<E, A> |
smullyan/task | Task<A>, TaskResult<E, A> |
smullyan/reader | Reader<R, A> |
The ADTs are not re-exported from the root: each defines map, flatMap, match and getOrElse, so they would collide. Import them by subpath.