import type { Either } from "../Either"; import { identity } from "../Function"; import { NoSuchElementException } from "../GlobalExceptions"; import type { Option } from "../Option"; import type { _E, _R } from "../support/utils"; import { isEither, isOption, isTag } from "../support/utils"; import type { Has, Tag } from "../Has"; import { fromEither, fromOption, succeed, suspend } from "./constructors"; import type { Sync } from "./model"; import { chain_ } from "./monad"; import { asksService } from "./service"; export class GenSync { readonly _R!: (_: R) => void; readonly _E!: () => E; readonly _A!: () => A; constructor(readonly S: Sync) {} *[Symbol.iterator](): Generator, A, any> { return yield this; } } const adapter = (_: any, __?: any) => { if (isEither(_)) { return new GenSync(fromEither(_)); } if (isOption(_)) { return new GenSync(fromOption(_, () => (__ ? __() : new NoSuchElementException("Sync.gen")))); } if (isTag(_)) { return new GenSync(asksService(_)(identity)); } return new GenSync(_); }; export function gen(): >( f: (i: { (_: Tag): GenSync, never, A>; (_: Option, onNone: () => E): GenSync; (_: Option): GenSync; (_: Either): GenSync; (_: Sync): GenSync; }) => Generator ) => Sync<_R, _E, A0>; export function gen(): >( f: (i: { (_: Tag): GenSync, never, A>; (_: Option, onNone: () => E): GenSync; (_: Option): GenSync; (_: Either): GenSync; (_: Sync): GenSync; }) => Generator ) => Sync<_R, _E, A0>; export function gen(): >( f: (i: { (_: Tag): GenSync, never, A>; (_: Option, onNone: () => E): GenSync; (_: Option): GenSync; (_: Either): GenSync; (_: Sync): GenSync; }) => Generator ) => Sync<_R, _E, A0>; export function gen, A>( f: (i: { (_: Tag): GenSync, never, A>; (_: Option, onNone: () => E): GenSync; (_: Option): GenSync; (_: Either): GenSync; (_: Sync): GenSync; }) => Generator ): Sync<_R, _E, A>; export function gen(...args: any[]): any { const _gen = , A>(f: (i: any) => Generator): Sync<_R, _E, A> => suspend(() => { const iterator = f(adapter as any); const state = iterator.next(); const run = (state: IteratorYieldResult | IteratorReturnResult): Sync => { if (state.done) { return succeed(state.value); } return chain_(state.value.S, (v) => { const next = iterator.next(v); return run(next); }); }; return run(state); }); if (args.length === 0) { return (f: any) => _gen(f); } return _gen(args[0]); }