// ets_tracing: off import * as L from "@effect-ts/system/Collections/Immutable/List" import { PrematureGeneratorExit } from "@effect-ts/system/GlobalExceptions" import { pipe } from "../../Function/index.js" import type * as HKT from "../HKT/index.js" import type { Monad } from "../Monad/index.js" import { chainF } from "./chain.js" import { succeedF } from "./succeed.js" export class GenHKT { constructor(readonly effect: T) {} *[Symbol.iterator](): Generator, A, any> { return yield this } } export class GenLazyHKT { constructor(readonly effect: () => T) {} *[Symbol.iterator](): Generator, A, any> { return yield this } } const adapter = (_: any) => { return new GenHKT(_) } const adapterLazy = (_: () => any) => { return new GenHKT(_) } /** * To be used with multi-shot monads, required adapter to be lazy * and is O(n^2) perf wise because the generator needs to be replayed */ export function genWithHistoryF< F extends HKT.URIS, C, ADAPTER = { ( _: () => HKT.Kind ): GenLazyHKT, A> } >( F: Monad, config?: { adapter?: ADAPTER } ): < Eff extends GenLazyHKT< HKT.Kind, any >, AEff >( f: (i: ADAPTER) => Generator ) => HKT.Kind< F, C, HKT.Infer>, HKT.Infer>, HKT.Infer>, HKT.Infer>, HKT.Infer>, HKT.Infer>, HKT.Infer>, HKT.Infer>, AEff > export function genWithHistoryF( F: Monad>, config?: { adapter?: { (_: () => HKT.HKT): GenLazyHKT, A> } } ): , any>, AEff>( f: (i: { (_: () => HKT.HKT): GenLazyHKT, A> }) => Generator ) => HKT.HKT { const chain = chainF(F) const succeed = succeedF(F) return , any>, AEff>( f: (i: { (_: () => HKT.HKT): GenLazyHKT, A> }) => Generator ): HKT.HKT => { return pipe( succeed({}), chain(() => { function run(replayStack: L.List): HKT.HKT { const iterator = f((config?.adapter ? config.adapter : adapterLazy) as any) let state = iterator.next() for (const a of replayStack) { if (state.done) { throw new PrematureGeneratorExit() } state = iterator.next(a) } if (state.done) { return succeed(state.value) } return chain((val) => { return run(L.append_(replayStack, val)) })(state.value["effect"]()) } return run(L.empty()) }) ) } } /** * To be used in one-shot monads, adapter is eager and perf is native */ export function genF< F extends HKT.URIS, C, ADAPTER = { (_: HKT.Kind): GenHKT< HKT.Kind, A > } >( F: Monad, config?: { adapter?: ADAPTER } ): < Eff extends GenHKT, any>, AEff >( f: (i: ADAPTER) => Generator ) => HKT.Kind< F, C, HKT.Infer, HKT.Infer, HKT.Infer, HKT.Infer, HKT.Infer, HKT.Infer, HKT.Infer, HKT.Infer, AEff > export function genF( F: Monad>, config?: { adapter?: { (_: HKT.HKT): GenHKT, A> } } ): , any>, AEff>( f: (i: { (_: HKT.HKT): GenHKT, A> }) => Generator ) => HKT.HKT { const chain = chainF(F) const succeed = succeedF(F) return , any>, AEff>( f: (i: { (_: HKT.HKT): GenHKT, A> }) => Generator ): HKT.HKT => { return pipe( succeed({}), chain(() => { const iterator = f((config?.adapter ? config.adapter : adapter) as any) const state = iterator.next() function run( state: IteratorYieldResult | IteratorReturnResult ): HKT.HKT { if (state.done) { return succeed(state.value) } return chain((val) => { const next = iterator.next(val) return run(next) })(state.value["effect"]) } return run(state) }) ) } }