import { bench, describe } from 'vitest'; import { STANDARD } from '../helpers/bench-options.js'; import { okSome, okNone, errNone, E, O, pipe, } from '../helpers/imports.js'; // --------------------------------------------------------------------------- // 5-step pipeline — OkSome path // --------------------------------------------------------------------------- describe('Query chaining — 5-step pipeline (all OkSome)', () => { bench('native-monad', () => { okSome(42) .map(x => x * 2) .flatMap(x => (x > 0 ? okSome(x) : okNone())) .map(x => ({ value: x })) .flatMap(x => okSome({ ...x, label: 'result' })) .map(x => JSON.stringify(x)); }, STANDARD); bench('fp-ts (nested)', () => { pipe( E.right(O.some(42)) as E.Either>, E.map(O.map(x => x * 2)), E.flatMap(inner => pipe( inner, O.match( () => E.right(O.none) as E.Either>, v => (v > 0 ? E.right(O.some(v)) : E.right(O.none)) as E.Either>, ), ), ), E.map(O.map(x => ({ value: x }))), E.flatMap(inner => pipe( inner, O.match( () => E.right(O.none) as E.Either>, v => E.right(O.some({ ...v, label: 'result' })), ), ), ), E.map(O.map(x => JSON.stringify(x))), ); }, STANDARD); }); // --------------------------------------------------------------------------- // ErrNone short-circuit — 9 no-op maps // --------------------------------------------------------------------------- describe('Query chaining — ErrNone at step 1, 9 no-op maps', () => { const nm = errNone('fail'); const fp = E.left('fail') as E.Either>; const fn = (x: number) => x + 1; bench('native-monad', () => { nm.map(fn).map(fn).map(fn).map(fn).map(fn).map(fn).map(fn).map(fn).map(fn); }, STANDARD); bench('fp-ts (nested)', () => { pipe( fp, E.map(O.map(fn)), E.map(O.map(fn)), E.map(O.map(fn)), E.map(O.map(fn)), E.map(O.map(fn)), E.map(O.map(fn)), E.map(O.map(fn)), E.map(O.map(fn)), E.map(O.map(fn)), ); }, STANDARD); }); // --------------------------------------------------------------------------- // OkNone short-circuit — 9 no-op maps // --------------------------------------------------------------------------- describe('Query chaining — OkNone, 9 no-op maps', () => { const nm = okNone(); const fp = E.right(O.none) as E.Either>; const fn = (x: number) => x + 1; bench('native-monad', () => { nm.map(fn).map(fn).map(fn).map(fn).map(fn).map(fn).map(fn).map(fn).map(fn); }, STANDARD); bench('fp-ts (nested)', () => { pipe( fp, E.map(O.map(fn)), E.map(O.map(fn)), E.map(O.map(fn)), E.map(O.map(fn)), E.map(O.map(fn)), E.map(O.map(fn)), E.map(O.map(fn)), E.map(O.map(fn)), E.map(O.map(fn)), ); }, STANDARD); }); // --------------------------------------------------------------------------- // 20-step deep map chain — OkSome path // --------------------------------------------------------------------------- describe('Query chaining — 20 maps on OkSome', () => { const fn = (x: number) => x + 1; bench('native-monad', () => { let r = okSome(0); for (let i = 0; i < 20; i++) r = r.map(fn); }, STANDARD); bench('fp-ts (nested)', () => { let r = E.right(O.some(0)) as E.Either>; for (let i = 0; i < 20; i++) r = pipe(r, E.map(O.map(fn))); }, STANDARD); });