fp
bun add @stopcock/fpEverything you need for pipe-based FP. Arrays, strings, objects, numbers, and typed error handling. Chain array operations in pipe and they get fused into single loops at runtime.
import { pipe, A, O, R } from '@stopcock/fp'
const topScorers = pipe( players, A.filter(p => p.active), A.map(p => ({ name: p.name, score: p.score })), A.sort((a, b) => b.score - a.score), A.take(10),)pipe(value, ...fns)passes a value through functions left to right. Fuses consecutiveA.*operations into a single loop.- Every function works both ways:
A.map(arr, fn)(data-first) andpipe(arr, A.map(fn))(data-last). Option<A>/Result<A, E>for nullable values and recoverable errors. Numeric_tagfor fast branching.
Modules
Section titled “Modules”| Namespace | Module | What it does |
|---|---|---|
A | Array | map, filter, reduce, sort, groupBy, zip, take, flatMap + 30 more |
S | String | split, trim, replace, startsWith, slice, padStart |
D | Dict | map, filter, get, merge, keys, values, toEntries |
N | Number | clamp, round, isEven, inRange, toFixed |
G | Guards | isString, isNumber, isArray, isNullable, isRecord |
Obj | Object | pick, omit, assoc, dissoc, mergeDeep, path, evolve |
M | Math | sum, mean, median, stddev, min, max, clamp |
B | Boolean | and, or, not, xor |
Logic | Logic | ifElse, when, unless, cond, allPass, anyPass |
Lens | Lenses | view, set, over for immutable nested updates |
O | Option | Some, None, map, flatMap, getOrElse, fromNullable |
R | Result | Ok, Err, map, flatMap, getOrElse, tryCatch |
Fusion
Section titled “Fusion”Chain fuseable operations in pipe and they get compiled into a single loop:
// This looks like 3 passes over the array:const result = pipe( users, // 100,000 users A.filter(u => u.active), // pass 1: filter A.map(u => u.name), // pass 2: map A.take(10), // pass 3: slice)
// But fusion compiles it into roughly:const result = []for (const u of users) { if (!u.active) continue result.push(u.name) if (result.length >= 10) break // early exit from take()}Option & Result
Section titled “Option & Result”// Option: for values that might not existconst port = pipe( O.fromNullable(process.env.PORT), O.map(s => parseInt(s, 10)), O.filter(n => n > 0 && n < 65536), O.getOrElse(() => 3000),)
// Result: for operations that might failconst config = pipe( R.tryCatch(() => JSON.parse(rawConfig)), R.map(obj => obj.settings), R.getOrElse(() => defaults),)Full docs on the Option & Result page, or have a look at the individual module pages in the sidebar.