/** * @typed/fp/Option is an extension to fp-ts/Option with stack-safe * ChainRec + MonadRec instances. * @since 0.9.2 */ import { ChainRec1 } from 'fp-ts/ChainRec' import * as E from 'fp-ts/Either' import { pipe } from 'fp-ts/function' import * as O from 'fp-ts/Option' import { MonadRec1 } from './MonadRec' import * as S from './struct' /** * @since 0.9.2 * @category Combinator */ export const chainRec = (f: (value: A) => O.Option>) => (value: A): O.Option => { let option = f(value) while (O.isSome(option)) { if (E.isRight(option.value)) { return O.some(option.value.right) } option = f(option.value.left) } return option } /** * @since 0.12.1 * @category Constructor */ export const struct = >>>( opts: Opts, ): O.Option<{ readonly [K in keyof Opts]: [Opts[K]] extends [O.Option] ? R : never }> => { const { concat } = O.getMonoid(S.getAssignSemigroup()) const entries = Object.entries(opts) return entries.reduce( (acc, [k, o]) => pipe( acc, concat( pipe( o, O.map((v) => S.make(k, v) as Opts), ), ), ), O.none as O.Option, ) } /** * @since 0.9.2 * @category Typeclass */ export const ChainRec: ChainRec1 = { chainRec, } /** * @since 0.9.2 * @category Typeclass */ export const MonadRec: MonadRec1 = { ...O.Monad, ...ChainRec, } export * from 'fp-ts/Option'