import * as E from 'fp-ts/Either' import { identity, Lazy, pipe } from 'fp-ts/function' import * as IO from 'fp-ts/IO' import * as IOE from 'fp-ts/IOEither' import * as O from 'fp-ts/Option' import * as R from 'fp-ts/Reader' import * as RE from 'fp-ts/ReaderEither' import * as RT from 'fp-ts/ReaderTask' import * as RTE from 'fp-ts/ReaderTaskEither' import * as T from 'fp-ts/Task' import * as TE from 'fp-ts/TaskEither' import { ValueOf } from '.' import * as $H from './Has' import * as $S from './struct' export const pick = () => (k: K) => RTE.asks((r: Pick) => r[k]) export const picks = () => ( k: K, f: (r: Pick[K]) => RTE.ReaderTaskEither, E, B>, ) => picksW()(k, f) export const picksW = () => ( k: K, f: (r: Pick[K]) => RTE.ReaderTaskEither, ) => pipe(pick()(k), RTE.chainW(f)) export const picksOptionK = () => (onNone: Lazy) => (k: K, f: (r: Pick[K]) => O.Option) => picks()(k, RTE.fromOptionK(onNone)(f)) export const picksEitherK = () => (k: K, f: (r: Pick[K]) => E.Either<_E, B>) => picks()(k, RTE.fromEitherK(f)) export const picksIOK = () => (k: K, f: (r: Pick[K]) => IO.IO) => pipe(pick()(k), RTE.chainIOK(f)) export const picksIOEitherK = () => ( k: K, f: (r: Pick[K]) => IOE.IOEither<_E, B>, ) => picks()(k, RTE.fromIOEitherK(f)) export const picksTaskK = () => (k: K, f: (r: Pick[K]) => T.Task) => pipe(pick()(k), RTE.chainTaskK(f)) export const picksTaskEitherK = () => ( k: K, f: (r: Pick[K]) => TE.TaskEither<_E, B>, ) => picks()(k, RTE.fromTaskEitherK(f)) export const read = (tag: $H.Tag) => pipe( RTE.ask<$H.Has>(), RTE.map((r) => r[tag.key]), ) export const readOption = (tag: $H.Tag>) => (onNone: Lazy) => pipe(read(tag), RTE.chainOptionK(onNone)(identity)) export const readEither = (tag: $H.Tag>) => pipe(read(tag), RTE.chainEitherKW(identity)) export const readIO = (tag: $H.Tag>) => pipe(read(tag), RTE.chainIOK(identity)) export const readIOEither = (tag: $H.Tag>) => pipe(read(tag), RTE.chainIOEitherKW(identity)) export const readTask = (tag: $H.Tag>) => pipe(read(tag), RTE.chainTaskK(identity)) export const readTaskEither = (tag: $H.Tag>) => pipe(read(tag), RTE.chainTaskEitherKW(identity)) export const readReader = (tag: $H.Tag>) => pipe(read(tag), RTE.chainReaderKW(identity)) export const readReaderEither = ( tag: $H.Tag>, ) => pipe(read(tag), RTE.chainReaderEitherKW(identity)) export const readReaderTask = (tag: $H.Tag>) => pipe(read(tag), RTE.chainReaderTaskKW(identity)) export const readReaderTaskEither = ( tag: $H.Tag>, ) => pipe(read(tag), RTE.flattenW) export const reads = ( tag: $H.Tag, key: K, ) => pipe( read(tag), RTE.map((a) => { const prop = a[key] return prop instanceof Function ? (prop.bind(a) as typeof prop) : prop }), ) export const readsOption = < A extends $S.Struct, K extends ValueOf<{ [K in keyof A]: A[K] extends O.Option ? K : never }>, >( tag: $H.Tag, key: K, ) => ( onNone: Lazy, ): A[K] extends O.Option ? RTE.ReaderTaskEither<$H.Has, E, B> : never => pipe( read(tag), RTE.chainOptionK(onNone)((a) => a[key] as any), ) as any export const readsEither = < A extends $S.Struct, K extends ValueOf<{ [K in keyof A]: A[K] extends E.Either ? K : never }>, >( tag: $H.Tag, key: K, ): A[K] extends E.Either ? RTE.ReaderTaskEither<$H.Has, E, B> : never => pipe( read(tag), RTE.chainEitherKW((a) => a[key] as any), ) as any export const readsIO = < A extends $S.Struct, K extends ValueOf<{ [K in keyof A]: A[K] extends IO.IO ? K : never }>, >( tag: $H.Tag, key: K, ): A[K] extends IO.IO ? RTE.ReaderTaskEither<$H.Has, never, B> : never => pipe( read(tag), RTE.chainIOK((a) => a[key] as any), ) as any export const readsIOEither = < A extends $S.Struct, K extends ValueOf<{ [K in keyof A]: A[K] extends IOE.IOEither ? K : never }>, >( tag: $H.Tag, key: K, ): A[K] extends IOE.IOEither ? RTE.ReaderTaskEither<$H.Has, E, B> : never => pipe( read(tag), RTE.chainIOEitherKW((a) => a[key] as any), ) as any export const readsTask = < A extends $S.Struct, K extends ValueOf<{ [K in keyof A]: A[K] extends T.Task ? K : never }>, >( tag: $H.Tag, key: K, ): A[K] extends T.Task ? RTE.ReaderTaskEither<$H.Has, never, B> : never => pipe( read(tag), RTE.chainTaskK((a) => a[key] as any), ) as any export const readsTaskEither = < A extends $S.Struct, K extends ValueOf<{ [K in keyof A]: A[K] extends TE.TaskEither ? K : never }>, >( tag: $H.Tag, key: K, ): A[K] extends TE.TaskEither ? RTE.ReaderTaskEither<$H.Has, E, B> : never => pipe( read(tag), RTE.chainTaskEitherKW((a) => a[key] as any), ) as any export const readsReader = < A extends $S.Struct, K extends ValueOf<{ [K in keyof A]: A[K] extends R.Reader ? K : never }>, >( tag: $H.Tag, key: K, ): A[K] extends R.Reader ? RTE.ReaderTaskEither, never, B> : never => pipe( read(tag), RTE.chainReaderKW((a) => a[key] as any), ) as any export const readsReaderEither = < A extends $S.Struct, K extends ValueOf<{ [K in keyof A]: A[K] extends RE.ReaderEither ? K : never }>, >( tag: $H.Tag, key: K, ): A[K] extends RE.ReaderEither ? RTE.ReaderTaskEither, E, B> : never => pipe( read(tag), RTE.chainReaderEitherKW((a) => a[key] as any), ) as any export const readsReaderTask = < A extends $S.Struct, K extends ValueOf<{ [K in keyof A]: A[K] extends RT.ReaderTask ? K : never }>, >( tag: $H.Tag, key: K, ): A[K] extends RT.ReaderTask ? RTE.ReaderTaskEither, never, B> : never => pipe( read(tag), RTE.chainReaderTaskKW((a) => a[key] as any), ) as any export const readsReaderTaskEither = < A extends $S.Struct, K extends ValueOf<{ [K in keyof A]: A[K] extends RTE.ReaderTaskEither ? K : never }>, >( tag: $H.Tag, key: K, ): A[K] extends RTE.ReaderTaskEither ? RTE.ReaderTaskEither, E, B> : never => pipe( read(tag), RTE.chainW((a) => a[key] as any), ) as any export const derive = any>(tag: $H.Tag) => ( ...args: Parameters any>> ): A extends (...args: any[]) => infer B ? RTE.ReaderTaskEither<$H.Has, never, B> : never => pipe( read(tag), RTE.map((f) => f(...args)), ) as any export const deriveOption = O.Option>(tag: $H.Tag) => (onNone: Lazy) => ( ...args: Parameters any>> ): A extends (...args: any[]) => O.Option ? RTE.ReaderTaskEither<$H.Has, E, B> : never => pipe( read(tag), RTE.chainOptionK(onNone)((f) => f(...args)), ) as any export const deriveEither = E.Either>(tag: $H.Tag) => ( ...args: Parameters any>> ): A extends (...args: any[]) => E.Either ? RTE.ReaderTaskEither<$H.Has, E, B> : never => pipe( read(tag), RTE.chainEitherKW((f) => f(...args)), ) as any export const deriveIO = IO.IO>(tag: $H.Tag) => ( ...args: Parameters any>> ): A extends (...args: any[]) => IO.IO ? RTE.ReaderTaskEither<$H.Has, never, B> : never => pipe( read(tag), RTE.chainIOK((f) => f(...args)), ) as any export const deriveIOEither = IOE.IOEither>( tag: $H.Tag, ) => ( ...args: Parameters any>> ): A extends (...args: any[]) => IOE.IOEither ? RTE.ReaderTaskEither<$H.Has, E, B> : never => pipe( read(tag), RTE.chainIOEitherKW((f) => f(...args)), ) as any export const deriveTask = T.Task>(tag: $H.Tag) => ( ...args: Parameters any>> ): A extends (...args: any[]) => T.Task ? RTE.ReaderTaskEither<$H.Has, never, B> : never => pipe( read(tag), RTE.chainTaskK((f) => f(...args)), ) as any export const deriveTaskEither = TE.TaskEither>( tag: $H.Tag, ) => ( ...args: Parameters any>> ): A extends (...args: any[]) => TE.TaskEither ? RTE.ReaderTaskEither<$H.Has, E, B> : never => pipe( read(tag), RTE.chainTaskEitherKW((f) => f(...args)), ) as any export const deriveReader = R.Reader>(tag: $H.Tag) => ( ...args: Parameters any>> ): A extends (...args: any[]) => R.Reader ? RTE.ReaderTaskEither, never, B> : never => pipe( read(tag), RTE.chainReaderKW((f) => f(...args)), ) as any export const deriveReaderEither = RE.ReaderEither>( tag: $H.Tag, ) => ( ...args: Parameters any>> ): A extends (...args: any[]) => RE.ReaderEither ? RTE.ReaderTaskEither, E, B> : never => pipe( read(tag), RTE.chainReaderEitherKW((f) => f(...args)), ) as any export const deriveReaderTask = RT.ReaderTask>( tag: $H.Tag, ) => ( ...args: Parameters any>> ): A extends (...args: any[]) => RT.ReaderTask ? RTE.ReaderTaskEither, never, B> : never => pipe( read(tag), RTE.chainReaderTaskKW((f) => f(...args)), ) as any export const deriveReaderTaskEither = RTE.ReaderTaskEither>( tag: $H.Tag, ) => ( ...args: Parameters any>> ): A extends ( ...args: any[] ) => RTE.ReaderTaskEither ? RTE.ReaderTaskEither, E, B> : never => pipe( read(tag), RTE.chainW((f) => f(...args)), ) as any export const derives = < A extends $S.Struct, K extends ValueOf<{ [K in keyof A]: A[K] extends (...args: any[]) => any ? K : never }>, >( tag: $H.Tag, key: K, ) => ( ...args: Parameters any>> ): A[K] extends (...args: any[]) => infer B ? RTE.ReaderTaskEither<$H.Has, never, B> : never => pipe( reads(tag, key), RTE.map((f) => (f as any)(...args)), ) as any export const derivesOption = < A extends $S.Struct, K extends ValueOf<{ [K in keyof A]: A[K] extends (...args: any[]) => O.Option ? K : never }>, >( tag: $H.Tag, key: K, ) => (onNone: Lazy) => ( ...args: Parameters any>> ): A[K] extends (...args: any[]) => O.Option ? RTE.ReaderTaskEither<$H.Has, E, B> : never => pipe( reads(tag, key), RTE.chainOptionK(onNone)((f) => (f as any)(...args)), ) as any export const derivesEither = < A extends $S.Struct, K extends ValueOf<{ [K in keyof A]: A[K] extends ( ...args: any[] ) => E.Either ? K : never }>, >( tag: $H.Tag, key: K, ) => ( ...args: Parameters any>> ): A[K] extends (...args: any[]) => E.Either ? RTE.ReaderTaskEither<$H.Has, E, B> : never => pipe( reads(tag, key), RTE.chainEitherKW((f) => (f as any)(...args)), ) as any export const derivesIO = < A extends $S.Struct, K extends ValueOf<{ [K in keyof A]: A[K] extends (...args: any[]) => IO.IO ? K : never }>, >( tag: $H.Tag, key: K, ) => ( ...args: Parameters any>> ): A[K] extends (...args: any[]) => IO.IO ? RTE.ReaderTaskEither<$H.Has, never, B> : never => pipe( reads(tag, key), RTE.chainIOK((f) => (f as any)(...args)), ) as any export const derivesIOEither = < A extends $S.Struct, K extends ValueOf<{ [K in keyof A]: A[K] extends ( ...args: any[] ) => IOE.IOEither ? K : never }>, >( tag: $H.Tag, key: K, ) => ( ...args: Parameters any>> ): A[K] extends (...args: any[]) => IOE.IOEither ? RTE.ReaderTaskEither<$H.Has, E, B> : never => pipe( reads(tag, key), RTE.chainIOEitherKW((f) => (f as any)(...args)), ) as any export const derivesTask = < A extends $S.Struct, K extends ValueOf<{ [K in keyof A]: A[K] extends (...args: any[]) => T.Task ? K : never }>, >( tag: $H.Tag, key: K, ) => ( ...args: Parameters any>> ): A[K] extends (...args: any[]) => T.Task ? RTE.ReaderTaskEither<$H.Has, never, B> : never => pipe( reads(tag, key), RTE.chainTaskK((f) => (f as any)(...args)), ) as any export const derivesTaskEither = < A extends $S.Struct, K extends ValueOf<{ [K in keyof A]: A[K] extends ( ...args: any[] ) => TE.TaskEither ? K : never }>, >( tag: $H.Tag, key: K, ) => ( ...args: Parameters any>> ): A[K] extends (...args: any[]) => TE.TaskEither ? RTE.ReaderTaskEither<$H.Has, E, B> : never => pipe( reads(tag, key), RTE.chainTaskEitherKW((f) => (f as any)(...args)), ) as any export const derivesReader = < A extends $S.Struct, K extends ValueOf<{ [K in keyof A]: A[K] extends (...args: any[]) => R.Reader ? K : never }>, >( tag: $H.Tag, key: K, ) => ( ...args: Parameters any>> ): A[K] extends (...args: any[]) => R.Reader ? RTE.ReaderTaskEither, never, B> : never => pipe( reads(tag, key), RTE.chainReaderKW((f) => (f as any)(...args)), ) as any export const derivesReaderEither = < A extends $S.Struct, K extends ValueOf<{ [K in keyof A]: A[K] extends ( ...args: any[] ) => RE.ReaderEither ? K : never }>, >( tag: $H.Tag, key: K, ) => ( ...args: Parameters any>> ): A[K] extends (...args: any[]) => RE.ReaderEither ? RTE.ReaderTaskEither, E, B> : never => pipe( reads(tag, key), RTE.chainReaderEitherKW((f) => (f as any)(...args)), ) as any export const derivesReaderTask = < A extends $S.Struct, K extends ValueOf<{ [K in keyof A]: A[K] extends ( ...args: any[] ) => RT.ReaderTask ? K : never }>, >( tag: $H.Tag, key: K, ) => ( ...args: Parameters any>> ): A[K] extends (...args: any[]) => RT.ReaderTask ? RTE.ReaderTaskEither, never, B> : never => pipe( reads(tag, key), RTE.chainReaderTaskKW((f) => (f as any)(...args)), ) as any export const derivesReaderTaskEither = < A extends $S.Struct, K extends ValueOf<{ [K in keyof A]: A[K] extends ( ...args: any[] ) => RTE.ReaderTaskEither ? K : never }>, >( tag: $H.Tag, key: K, ) => ( ...args: Parameters any>> ): A[K] extends ( ...args: any[] ) => RTE.ReaderTaskEither ? RTE.ReaderTaskEither, E, B> : never => pipe( reads(tag, key), RTE.chainW((f) => (f as any)(...args)), ) as any