@typed/fp
Version:
Data Structures and Resources for fp-ts
555 lines • 11.6 kB
JavaScript
/**
* `Env` is the core of the higher-level modules like [Ref](./Ref.ts.md) and is a `ReaderT` of [Resume](./Resume.ts.md); but
* to be honest, being used so much, I didn't like writing `ReaderResume<E, A>` and chose to shorten to
* `Env<E, A>` for the "environmental" quality Reader provides. Combining Reader and Resume allows for
* creating APIs capable of utilizing dependency injection for their configuration and testability
* while still combining your sync/async workflows.
*
* While designing application APIs it is often better to describe the logic of your system separate
* from the implementation details. `Env` or rather `Reader` helps you accomplish this through the
* [Dependency Inversion Principle](https://alexnault.dev/dependency-inversion-principle-in-functional-typescript).
* This principle is one of the easiest ways to begin improving any codebase.
*
* @since 0.9.2
*/
import { disposeNone } from '@most/disposable';
import * as Alt_ from 'fp-ts/Alt';
import * as FpApplicative from 'fp-ts/Applicative';
import * as Ap from 'fp-ts/Apply';
import * as FpChain from 'fp-ts/Chain';
import * as FIO from 'fp-ts/FromIO';
import * as FR from 'fp-ts/FromReader';
import * as FT from 'fp-ts/FromTask';
import * as FN from 'fp-ts/function';
import { bindTo as bindTo_, flap as flap_, tupled as tupled_ } from 'fp-ts/Functor';
import * as RT from 'fp-ts/ReaderT';
import * as RA from 'fp-ts/ReadonlyArray';
import { traverse } from 'fp-ts/ReadonlyArray';
import * as FRe from './FromResume';
import * as P from './Provide';
import * as R from './Resume';
import * as St from './struct';
/**
* @since 0.9.2
* @category Combinator
*/
export const ap = RT.ap(R.Apply);
/**
* @since 0.9.2
* @category Combinator
*/
export const apW = RT.ap(R.Apply);
/**
* @since 0.9.2
* @category Combinator
*/
export const chain = RT.chain(R.Chain);
/**
* @since 0.9.2
* @category Combinator
*/
export const chainW = RT.chain(R.Chain);
/**
* @since 0.9.2
* @category Constructor
*/
export const fromReader = RT.fromReader(R.Pointed);
/**
* @since 0.9.2
* @category Combinator
*/
export const map = RT.map(R.Functor);
/**
* @since 0.9.2
* @category Combinator
*/
export const tap = (f) => (fa) => FN.pipe(fa, map((a) => {
f(a);
return a;
}));
/**
* @since 0.9.2
* @category Combinator
*/
export const constant = FN.flow(FN.constant, map);
/**
* @since 0.9.2
* @category Constructor
*/
export const of = RT.of(R.Pointed);
/**
* @since 0.9.2
* @category Constructor
*/
export const asksIOK = RT.fromNaturalTransformation(R.fromIO);
/**
* @since 0.9.2
* @category Constructor
*/
export const asksTaskK = RT.fromNaturalTransformation(R.fromTask);
/**
* @since 0.9.2
* @category Combinator
*/
export function chainRec(f) {
return (value) => (env) => R.chainRec((a) => f(a)(env))(value);
}
/**
* @since 0.9.2
* @category URI
*/
export const URI = '@typed/fp/Env';
/**
* @since 0.9.2
* @category Instance
*/
export const Pointed = {
of,
};
/**
* @since 0.9.2
* @category Instance
*/
export const Functor = {
URI,
map,
};
/**
* @since 0.9.2
* @category Combinator
*/
export const flap = flap_(Functor);
/**
* @since 0.9.2
* @category Instance
*/
export const Apply = {
...Functor,
ap,
};
/**
* @since 0.9.2
* @category Combinator
*/
export const apS = Ap.apS(Apply);
/**
* @since 0.9.2
* @category Combinator
*/
export const apSW = apS;
/**
* @since 0.9.2
* @category Combinator
*/
export const apT = Ap.apT(Apply);
/**
* @since 0.9.2
* @category Combinator
*/
export const apTW = apT;
/**
* @since 0.9.2
* @category Combinator
*/
export const apFirst = Ap.apFirst(Apply);
/**
* @since 0.9.2
* @category Combinator
*/
export const apFirstW = apFirst;
/**
* @since 0.9.2
* @category Combinator
*/
export const apSecond = Ap.apSecond(Apply);
/**
* @since 0.9.2
* @category Combinator
*/
export const apSecondW = apSecond;
/**
* @since 0.9.2
* @category Typeclass Constructor
*/
export const getSemigroup = Ap.getApplySemigroup(Apply);
/**
* @since 0.9.2
* @category Instance
*/
export const Applicative = {
...Apply,
...Pointed,
};
/**
* @since 0.9.2
* @category Typeclass Constructor
*/
export const getMonoid = FpApplicative.getApplicativeMonoid(Applicative);
/**
* @since 0.9.2
* @category Instance
*/
export const Chain = {
...Functor,
chain,
};
/**
* @since 0.9.2
* @category Combinator
*/
export const chainFirst = FpChain.chainFirst(Chain);
/**
* @since 0.9.2
* @category Combinator
*/
export const chainFirstW = chainFirst;
/**
* @since 0.9.2
* @category Combinator
*/
export const flattenW = chain(FN.identity);
/**
* @since 0.9.2
* @category Combinator
*/
export const flatten = chain(FN.identity);
/**
* @since 0.9.2
* @category Instance
*/
export const Monad = {
...Chain,
...Pointed,
};
/**
* @since 0.9.2
* @category Instance
*/
export const ChainRec = {
URI,
chainRec,
};
/**
* @since 0.9.2
* @category Instance
*/
export const MonadRec = {
...Monad,
chainRec,
};
/**
* @since 0.9.2
* @category Instance
*/
export const FromReader = {
fromReader: (reader) => (e) => R.sync(() => reader(e)),
};
/**
* @since 0.9.2
* @category Combinator
*/
export const raceW = (a) => (b) => (e) => R.race(a(e))(b(e));
/**
* @since 0.9.2
* @category Combinator
*/
export const race = (a) => (b) => (e) => R.race(a(e))(b(e));
/**
* @since 0.9.2
* @category Instance
*/
export const Alt = {
...Functor,
alt: (snd) => (fst) => raceW(fst)(snd()),
};
/**
* @since 0.9.2
* @category Combinator
*/
export const alt = Alt.alt;
/**
* @since 0.9.2
* @category Combinator
*/
export const altW = alt;
/**
* @since 0.9.2
* @category Combinator
*/
export const altAll = Alt_.altAll(Alt);
/**
* @since 0.9.2
* @category Constructor
*/
export const fromIO = fromReader;
/**
* @since 0.9.2
* @category Instance
*/
export const FromIO = {
URI,
fromIO,
};
/**
* @since 0.9.2
* @category Instance
*/
export const FromTask = {
...FromIO,
fromTask: (task) => () => R.fromTask(task),
};
/**
* @since 0.9.2
* @category Constructor
*/
export const fromTask = FromTask.fromTask;
/**
* @since 0.9.2
* @category Constructor
*/
export const fromResume = FN.constant;
/**
* @since 0.9.2
* @category Combinator
*/
export const FromResume = {
fromResume,
};
/**
* @since 0.9.2
* @category Combinator
*/
export const useSome = (provided) => (env) => (e) => env({ ...e, ...provided });
/**
* @since 0.9.2
* @category Combinator
*/
export const provideSome = (provided) => (env) => (e) => env({ ...provided, ...e });
/**
* @since 0.9.2
* @category Combinator
*/
export const useAll = (provided) => (env) => () => env(provided);
/**
* @since 0.9.2
* @category Combinator
*/
export const provideAll = (provided) => (env) => (e) => { var _a; return env({ ...provided, ...((_a = e) !== null && _a !== void 0 ? _a : {}) }); };
/**
* @since 0.9.2
* @category Instance
*/
export const UseSome = {
useSome,
};
/**
* @since 0.9.2
* @category Instance
*/
export const UseAll = {
useAll,
};
/**
* @since 0.9.2
* @category Instance
*/
export const ProvideSome = {
provideSome,
};
/**
* @since 0.9.2
* @category Instance
*/
export const ProvideAll = {
provideAll,
};
/**
* @since 0.9.2
* @category Combinator
*/
export const provideAllWith = P.provideAllWith({ ...ProvideAll, ...Chain });
/**
* @since 0.9.2
* @category Combinator
*/
export const useAllWith = P.useAllWith({ ...UseAll, ...Chain });
/**
* @since 0.9.2
* @category Combinator
*/
export const provideSomeWith = P.provideSomeWith({ ...ProvideSome, ...Chain });
/**
* @since 0.9.2
* @category Combinator
*/
export const useSomeWith = P.useSomeWith({ ...UseSome, ...Chain });
/**
* @since 0.9.2
* @category Combinator
*/
export const askAndUse = P.askAndUse({ ...UseAll, ...Chain, ...FromReader });
/**
* @since 0.9.2
* @category Combinator
*/
export const askAndProvide = P.askAndProvide({ ...ProvideAll, ...Chain, ...FromReader });
/**
* @since 0.9.2
* @category Combinator
*/
export const toResume = FN.flow(askAndUse, map((e) => e({})));
/**
* @since 0.9.2
* @category Instance
*/
export const Provide = {
useSome,
useAll,
provideSome,
provideAll,
};
/**
* @since 0.9.2
* @category Constructor
*/
export const Do = fromIO(() => Object.create(null));
/**
* @since 0.9.2
* @category Combinator
*/
export const bindTo = bindTo_(Functor);
/**
* @since 0.9.2
* @category Combinator
*/
export const bind = FpChain.bind(Monad);
/**
* @since 0.9.2
* @category Combinator
*/
export const bindW = FpChain.bind(Monad);
/**
* @since 0.9.2
* @category Combinator
*/
export const tupled = tupled_(Functor);
/**
* @since 0.9.2
* @category Constructor
*/
export const ask = FR.ask(FromReader);
/**
* @since 0.9.2
* @category Constructor
*/
export const asks = FR.asks(FromReader);
/**
* @since 0.9.2
* @category Constructor
*/
export const asksE = FN.flow(asks, flattenW);
/**
* @since 0.9.2
* @category Combinator
*/
export const chainReaderK = FR.chainReaderK(FromReader, Chain);
/**
* @since 0.9.2
* @category Constructor
*/
export const fromReaderK = FR.fromReaderK(FromReader);
/**
* @since 0.9.2
* @category Combinator
*/
export const chainFirstResumeK = FRe.chainFirstResumeK(FromResume, Chain);
/**
* @since 0.9.2
* @category Combinator
*/
export const chainResumeK = FRe.chainResumeK(FromResume, Chain);
/**
* @since 0.9.2
* @category Constructor
*/
export const fromResumeK = FRe.fromResumeK(FromResume);
/**
* @since 0.9.2
* @category Combinator
*/
export const chainFirstTaskK = FT.chainFirstTaskK(FromTask, Chain);
/**
* @since 0.9.2
* @category Combinator
*/
export const chainTaskK = FT.chainTaskK(FromTask, Chain);
/**
* @since 0.9.2
* @category Constructor
*/
export const fromTaskK = FT.fromTaskK(FromTask);
/**
* @since 0.9.2
* @category Combinator
*/
export const chainFirstIOK = FIO.chainFirstIOK(FromIO, Chain);
/**
* @since 0.9.2
* @category Combinator
*/
export const chainIOK = FIO.chainIOK(FromIO, Chain);
/**
* @since 0.9.2
* @category Constructor
*/
export const fromIOK = FIO.fromIOK(FromIO);
/**
* @since 0.9.2
* @category Combinator
*/
export const zip = traverse(Applicative)((x) => x);
/**
* @since 0.9.2
* @category Combinator
*/
export const zipW = zip;
/**
* @since 0.9.2
* @category Combinator
*/
export const combineAll = (...envs) => zipW(envs);
/**
* @since 0.11.0
* @category Combinator
*/
export const combineStruct = (props) => FN.pipe(combineAll(...FN.pipe(Object.entries(props), RA.map(([k, env]) => FN.pipe(env, map((v) => St.make(k, v)))))), map((o) => Object.assign({}, ...o)));
/**
* @since 0.9.2
* @category Execution
*/
export const runWith = (f) => (requirements) => (env) => FN.pipe(requirements, env, R.run(f));
/**
* @since 0.9.2
* @category Execution
*/
export const execWith = runWith(disposeNone);
/**
* Construct an Env to a lazily-defined Env-based effect that must be provided later.
* Does not support functions which require type-parameters as they will resolve to unknown, due
* to limitations in TS, if you need this maybe use [asksE](#askse)
* @since 0.9.2
* @category Constructor
*/
export const op = () => (key) => {
function operation(...args) {
return FN.pipe(ask(), chain((e) => e[key](...args)));
}
operation.key = key;
return operation;
};
/**
* @since 0.9.2
* @category Combinator
*/
export const toResumeK = (envK) => FN.pipe(ask(), map((e) => (...args) => FN.pipe(e, envK(...args))));
//# sourceMappingURL=Env.js.map