import { bench, describe } from 'vitest'; import { STANDARD } from '../helpers/bench-options.js'; import { some, none, TsSome, TsNone, OxSome, OxNone, O, pipe, TmMaybe, } from '../helpers/imports.js'; // --------------------------------------------------------------------------- // 5-step pipeline — Some path // --------------------------------------------------------------------------- describe('Option chaining — 5-step pipeline (all Some)', () => { bench('native-monad', () => { some(42) .map(x => x * 2) .flatMap(x => (x > 0 ? some(x) : none())) .map(x => ({ value: x })) .flatMap(x => some({ ...x, label: 'result' })) .map(x => JSON.stringify(x)); }, STANDARD); bench('ts-results-es', () => { TsSome(42) .map(x => x * 2) .andThen(x => (x > 0 ? TsSome(x) : TsNone)) .map(x => ({ value: x })) .andThen(x => TsSome({ ...x, label: 'result' })) .map(x => JSON.stringify(x)); }, STANDARD); bench('oxide.ts', () => { OxSome(42) .map(x => x * 2) .andThen(x => (x > 0 ? OxSome(x) : OxNone)) .map(x => ({ value: x })) .andThen(x => OxSome({ ...x, label: 'result' })) .map(x => JSON.stringify(x)); }, STANDARD); bench('fp-ts', () => { pipe( O.some(42), O.map(x => x * 2), O.flatMap(x => (x > 0 ? O.some(x) : O.none)), O.map(x => ({ value: x })), O.flatMap(x => O.some({ ...x, label: 'result' })), O.map(x => JSON.stringify(x)), ); }, STANDARD); bench('true-myth', () => { TmMaybe.just(42) .map(x => x * 2) .andThen(x => (x > 0 ? TmMaybe.just(x) : TmMaybe.nothing())) .map(x => ({ value: x })) .andThen(x => TmMaybe.just({ ...x, label: 'result' })) .map(x => JSON.stringify(x)); }, STANDARD); }); // --------------------------------------------------------------------------- // None short-circuit — 9 no-op maps // --------------------------------------------------------------------------- describe('Option chaining — None at step 1, 9 no-op maps', () => { const nmNone = none(); const tsNone = TsNone; const oxNone = OxNone; const fpNone = O.none; const tmNone = TmMaybe.nothing(); const fn = (x: number) => x + 1; bench('native-monad', () => { nmNone.map(fn).map(fn).map(fn).map(fn).map(fn).map(fn).map(fn).map(fn).map(fn); }, STANDARD); bench('ts-results-es', () => { tsNone.map(fn).map(fn).map(fn).map(fn).map(fn).map(fn).map(fn).map(fn).map(fn); }, STANDARD); bench('oxide.ts', () => { oxNone.map(fn).map(fn).map(fn).map(fn).map(fn).map(fn).map(fn).map(fn).map(fn); }, STANDARD); bench('fp-ts', () => { pipe(fpNone, O.map(fn), O.map(fn), O.map(fn), O.map(fn), O.map(fn), O.map(fn), O.map(fn), O.map(fn), O.map(fn)); }, STANDARD); bench('true-myth', () => { tmNone.map(fn).map(fn).map(fn).map(fn).map(fn).map(fn).map(fn).map(fn).map(fn); }, STANDARD); }); // --------------------------------------------------------------------------- // 20-step deep map chain — Some path // --------------------------------------------------------------------------- describe('Option chaining — 20 maps on Some', () => { const fn = (x: number) => x + 1; bench('native-monad', () => { let r = some(0); for (let i = 0; i < 20; i++) r = r.map(fn); }, STANDARD); bench('ts-results-es', () => { let r = TsSome(0); for (let i = 0; i < 20; i++) r = r.map(fn) as any; }, STANDARD); bench('oxide.ts', () => { let r = OxSome(0); for (let i = 0; i < 20; i++) r = r.map(fn) as any; }, STANDARD); bench('fp-ts', () => { let r = O.some(0) as O.Option; for (let i = 0; i < 20; i++) r = pipe(r, O.map(fn)); }, STANDARD); bench('true-myth', () => { let r = TmMaybe.just(0); for (let i = 0; i < 20; i++) r = r.map(fn) as any; }, STANDARD); });