import type { BindToSFn } from './Functor' import type { Monad } from './Monad' import { flow, pipe } from './function' import * as HKT from './HKT' export interface Do extends Monad { readonly bindS: BindSFn readonly letS: LetSFn readonly bindToS: BindToSFn } export function Do(M: Monad): Do export function Do(M: Monad>): Do> { const bindS: BindSFn> = (name, f) => flow( M.bind((a) => pipe( f(a), M.map((b) => Object.assign({}, a, { [name]: b } as any)) ) ) ) return HKT.instance>>({ ...M, bindS, letS: (name, f) => bindS(name, flow(f, M.pure)), bindToS: (name) => (ma) => M.map_(ma, (a) => ({ [name]: a } as any)) }) } export interface BindSFn { ( name: Exclude, f: (a: A) => HKT.Kind ): ( fa: HKT.Kind< F, C, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, HKT.Intro, A > ) => HKT.Kind< F, C, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, HKT.Mix, { [K in keyof A | BN]: K extends keyof A ? A[K] : A1 } > } export function bindSF(F: Monad): BindSFn { return (name, f) => F.bind((a) => pipe( f(a), F.map((b) => Object.assign({}, a, { [name]: b })) ) ) } export interface LetSFn { (name: Exclude, f: (a: A) => A1): ( fa: HKT.Kind ) => HKT.Kind } export function letSF(F: Monad): LetSFn { return (name, f) => F.bind((a) => pipe( f(a), F.pure, F.map((b) => Object.assign({}, a, { [name]: b })) ) ) }