import { chainF } from "@principia/prelude/Chain"; import type * as HKT from "@principia/prelude/HKT"; import type { Monad } from "@principia/prelude/Monad"; import { pureF } from "@principia/prelude/Pure"; import { pipe } from "../Function"; import { PrematureGeneratorExit } from "../GlobalExceptions"; export class GenHKT { constructor(readonly T: T) {} *[Symbol.iterator](): Generator, A, any> { return yield this; } } const adapter = (_: any) => { return new GenHKT(_); }; export function genWithHistoryF< F extends HKT.URIS, TC, Adapter = { (_: HKT.Kind): GenHKT< HKT.Kind, A >; } >( M: Monad, config?: { adapter?: Adapter } ): , any>, A0>( f: (i: Adapter) => Generator ) => HKT.Kind< F, TC, HKT.Infer, HKT.Infer, HKT.Infer, HKT.Infer, HKT.Infer, HKT.Infer, HKT.Infer, HKT.Infer, HKT.Infer, A0 >; export function genWithHistoryF( F: Monad>, config?: { adapter?: { (_: HKT.HKT): GenHKT, A>; }; } ): , any>, AEff>( f: (i: { (_: HKT.HKT): GenHKT, A> }) => Generator ) => HKT.HKT { const chain = chainF(F); const pure = pureF(F); return , any>, AEff>( f: (i: { (_: HKT.HKT): GenHKT, A> }) => Generator ): HKT.HKT => { return pipe( pure({}), chain(() => { function run(replayStack: any[]): HKT.HKT { const iterator = f((config?.adapter ? config.adapter : adapter) as any); let state = iterator.next(); for (let i = 0; i < replayStack.length; i++) { if (state.done) { throw new PrematureGeneratorExit("GenHKT.genWithHistoryF"); } state = iterator.next(replayStack[i]); } if (state.done) { return pure(state.value); } return chain((val) => { return run(replayStack.concat([val])); })(state.value["T"]); } return run([]); }) ); }; } export function genF< F extends HKT.URIS, TC, Adapter = { (_: HKT.Kind): GenHKT< HKT.Kind, A >; } >( M: Monad, config?: { adapter?: Adapter } ): , any>, A0>( f: (i: Adapter) => Generator ) => HKT.Kind< F, TC, HKT.Infer, HKT.Infer, HKT.Infer, HKT.Infer, HKT.Infer, HKT.Infer, HKT.Infer, HKT.Infer, HKT.Infer, A0 >; 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 pure = pureF(F); return , any>, AEff>( f: (i: { (_: HKT.HKT): GenHKT, A> }) => Generator ): HKT.HKT => { return pipe( pure({}), 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 pure(state.value); } return chain((val) => { const next = iterator.next(val); return run(next); })(state.value["T"]); } return run(state); }) ); }; }