import { Flatten, UnNest } from '@typed/common' import { Env, Pure, withEnv as runWithEnv } from '@typed/env' import { Fn } from '@typed/lambda' export interface Effects extends Effect, B> {} export interface Effect extends Generator {} export type TypeOf = A extends Effect ? Effects, Return> : A extends (...args: readonly any[]) => Effects ? Effects>, Return>> : unknown export interface Computation extends Fn> {} // An individual effect export type PureEffect = Effect, A> export type Yield = A extends Effect ? R : never export type Return = A extends Effect ? R : never export type Capabilities = A extends Effects ? R : never export namespace Effect { export function of(value: A): PureEffect { return fromEnv(Pure.of(value)) } export function fromEnv(env: Env): Effect, B> export function fromEnv(pure: Pure): Effect, A> export function* fromEnv(env: Env): Effect, B> { return yield env } export function* withEnv(fn: (env: A) => Effects): Effects { const effect: Effects = yield runWithEnv(fn) return yield* effect } } export type IteratorResultOf = IteratorResult, Return> export type CombinedCapabilities>> = UnNest< Flatten, {}> > export type CombinedValues>> = { readonly [K in keyof A]: Return } type ToConsList = [] extends A ? unknown : ((...a: A) => any) extends (t: infer T, ...ts: infer TS) => any ? [Capabilities, ToConsList] : never