import type { Has, Tag } from './Has' import type { MonadMin } from './Monad' import { pureF } from './Applicative' import { bindF_ } from './Bind' import { flow, identity, pipe } from './function' import * as HKT from './HKT' import { Monad } from './Monad' /** * Contravariant `Reader` + `Monad` */ export interface MonadEnv> extends Monad { readonly asks: AsksFn readonly ask: AskFn readonly asksM: AsksMFn readonly giveAll_: GiveAllFn_ readonly giveAll: GiveAllFn readonly gives_: GivesFn_ readonly gives: GivesFn } export type MonadEnvMin> = MonadMin & { readonly asks: AsksFn readonly giveAll_: GiveAllFn_ } export function MonadEnv>(M: MonadEnvMin): MonadEnv { return HKT.instance>({ ...Monad(M), giveAll_: M.giveAll_, giveAll: (r) => (fa) => M.giveAll_(fa, r), asks: M.asks, ask: askF(M), asksM: asksMF(M), gives_: givesF_(M), gives: givesF(M) }) } export interface AskFn> { < R, N extends string = HKT.Initial, K = HKT.Initial, Q = HKT.Initial, W = HKT.Initial, X = HKT.Initial, I = HKT.Initial, S = HKT.Initial, E = HKT.Initial >(): HKT.Kind } export function askF>(F: MonadEnvMin): AskFn { return () => F.asks(pureF(F)) } export interface AsksFn> { < A, N extends string = HKT.Initial, K = HKT.Initial, Q = HKT.Initial, W = HKT.Initial, X = HKT.Initial, I = HKT.Initial, S = HKT.Initial, R = HKT.Initial, E = HKT.Initial >( f: (_: R) => A ): HKT.Kind } export interface AsksMFn> { ( f: (_: HKT.OrFix<'R', C, R0>) => HKT.Kind ): HKT.Kind, E, A> } export interface GiveAllFn> { (r: R): ( fa: HKT.Kind ) => HKT.Kind } export interface GiveAllFn_> { (fa: HKT.Kind, r: R): HKT.Kind< F, TC, N, K, Q, W, X, I, S, unknown, E, A > } export interface GiveFn> { (r: R): ( ma: HKT.Kind ) => HKT.Kind } export interface GiveFn_> { ( ma: HKT.Kind, r: R ): HKT.Kind } export interface GivesFn> { (f: (r0: R0) => R): ( ma: HKT.Kind ) => HKT.Kind } export interface GivesFn_> { ( ma: HKT.Kind, f: (r0: R0) => R ): HKT.Kind } export interface AsksServiceFn> { (H: Tag): < A, N extends string = HKT.Initial, K = HKT.Initial, Q = HKT.Initial, W = HKT.Initial, X = HKT.Initial, I = HKT.Initial, S = HKT.Initial, R = HKT.Initial, E = HKT.Initial >( f: (_: Service) => A ) => HKT.Kind, E, A> } export interface AsksServiceMFn> { (H: Tag): ( f: (_: Service) => HKT.Kind ) => HKT.Kind, E, A> } export interface GiveServiceFn> { (H: Tag): ( S: Service ) => ( ma: HKT.Kind, E, A> ) => HKT.Kind } export interface GiveServiceMFn> { (H: Tag): ( S: HKT.Kind ) => ( ma: 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, R & R1, HKT.Mix, A > } /** * Derives from `MonadEnv`: * ```haskell * gives :: (MonadEnv m) => (r0 -> r) -> m r a -> m r0 a * ``` */ export function givesF_>(F: MonadEnvMin): GivesFn_ export function givesF_(F: MonadEnvMin, HKT.V<'R', '-'>>): GivesFn_, HKT.V<'R', '-'>> { return (ma: HKT.HKT3, f: (_: R0) => R): HKT.HKT3 => asksMF(F)((r0: R0) => F.giveAll_(ma, f(r0))) } /** * Derives from `MonadEnv`: * ```haskell * gives :: (MonadEnv m) => (r0 -> r) -> m r a -> m r0 a * ``` */ export function givesF>(F: MonadEnvMin): GivesFn export function givesF(F: MonadEnvMin, HKT.V<'R', '-'>>): GivesFn, HKT.V<'R', '-'>> { return (f: (_: R0) => R) => (ma: HKT.HKT3): HKT.HKT3 => asksMF(F)((r0: R0) => F.giveAll_(ma, f(r0))) } /** * Derives from `MonadEnv`: * ```haskell * give :: (MonadEnv m) => r -> m |r & r0| a -> m r0 a * ``` */ export function giveF>(F: MonadEnv): GiveFn export function giveF(F: MonadEnv, HKT.V<'R', '-'>>): GiveFn, HKT.V<'R', '-'>> { return (r: R) => (ma: HKT.HKT3): HKT.HKT3 => asksMF(F)((r0: R0) => F.giveAll_(ma, { ...r, ...r0 })) } /** * Derives from `MonadEnv`: * ```haskell * asksM :: (MonadEnv m) => (r0 -> m r a) -> m |r0 & r| a * ``` */ export function asksMF>(F: MonadEnvMin): AsksMFn { const bind_ = bindF_(F) return flow(F.asks, (mma) => bind_(mma, identity)) } /** * Derives from `MonadEnv`: * ```haskell * asksService :: (MonadEnv m) => (Tag s) => (s -> a) -> m s a * ``` */ export function asksServiceF>(F: MonadEnv): AsksServiceFn { return (H) => (f) => F.asks((_) => pipe(_, H.read, f)) } /** * Derives from `MonadEnv`: * ```haskell * asksService :: (MonadEnv m) => (Tag s) => (s -> m r a) -> m |s & r| a * ``` */ export function asksServiceMF>(F: MonadEnv): AsksServiceMFn { return (H) => (f) => asksMF(F)(flow(H.read, f)) } /** * Derives from `MonadEnv`: * ```haskell * giveService :: (MonadEnv m) => (Tag s) => s -> m |s & r| a -> m r a * ``` */ export function giveServiceF>(F: MonadEnv): GiveServiceFn { return (H) => (S) => (ma) => asksMF(F)((r) => F.giveAll_(ma, { ...r, [H.key]: S } as any)) } /** * Derives from `MonadEnv`: * ```haskell * giveService :: (MonadEnv m) => (Tag s) => m r0 s -> m |s & r| a -> m |r & r0| a * ``` */ export function giveServiceMF>(F: MonadEnv): GiveServiceMFn export function giveServiceMF(F: MonadEnv, HKT.V<'R', '-'>>) { return (H: Tag) => (S: HKT.HKT3) => ( ma: HKT.HKT3, E, A> ) => asksMF(F)((r: R) => pipe(S, (mas) => F.bind_(mas, (svc) => F.giveAll_(ma, { ...r, [H.key]: svc } as any)))) }