UNPKG

fp-ts-bracket

Version:
421 lines (420 loc) 10.1 kB
/** * The Bracket module provides provides a monadic interface over TE.bracket. * * @since 1.0.0 */ /* eslint-disable @typescript-eslint/no-explicit-any */ import { apFirst as apFirst_, apS as apS_, apSecond as apSecond_, sequenceS as sequenceS_, sequenceT as sequenceT_, } from "fp-ts/lib/Apply"; import { bind as bind_ } from "fp-ts/lib/Chain"; import * as E from "fp-ts/lib/Either"; import { pipe } from "fp-ts/lib/function"; import { bindTo as bindTo_, flap as flap_, let as let_, } from "fp-ts/lib/Functor"; import * as O from "fp-ts/lib/Option"; import * as RA from "fp-ts/lib/ReadonlyArray"; import * as RNEA from "fp-ts/lib/ReadonlyNonEmptyArray"; import * as TE from "fp-ts/lib/TaskEither"; import { asUnit as asUnit_, as as as_, tapEither as tapEither_, tapIO as tapIO_, tapTask as tapTask_, tap as tap_, } from "./internal"; import { dual } from "./internalGenreics"; /** * @category type lambdas * @since 1.0.0 */ export const URI = "Bracket"; /** * @category instances * @since 1.0.0 */ export const Bracket = (acquire, dispose) => (use) => TE.bracket(acquire, use, dispose); /** * @category utils * @since 1.0.0 */ export const use = (use) => (bracket) => bracket(use); /** * @category instances * @since 1.0.0 */ export const Pointed = { URI: URI, of: (x) => (use) => use(x), }; /** * @category constructors * @since 1.0.0 */ export const of = (x) => Pointed.of(x); /** * @category utils * @since 1.0.0 */ export const noDispose = () => TE.of(undefined); /** * @category conversions * @since 1.0.0 */ export const fromIO = (fa) => Bracket(TE.fromIO(fa), noDispose); /** * @category instances * @since 1.0.0 */ export const FromIO = { URI, fromIO, }; /** * @category conversions * @since 1.0.0 */ export const fromTask = (fa) => Bracket(TE.fromTask(fa), noDispose); /** * @category instances * @since 1.0.0 */ export const FromTask = { URI, fromIO, fromTask, }; /** * @category conversions * @since 1.0.0 */ export const fromTaskEither = (fa) => Bracket(fa, noDispose); /** * alias for fromTaskEither * * @category constructors * @since 1.0.0 */ export const fromAcquire = fromTaskEither; /** * @category conversions * @since 1.0.0 */ export const fromEither = (fa) => Bracket(TE.fromEither(fa), noDispose); /** * @category instances * @since 1.0.0 */ export const FromEither = { URI, fromEither, }; /** * @category instances * @since 1.0.0 */ export const Functor = { URI: URI, map: (fa, f) => (use) => fa((a) => use(f(a))), }; /** * @category mapping * @since 1.0.0 */ export const map = (f) => (fa) => Functor.map(fa, f); /** * Maps the value to the specified constant value. * * @category mapping * @since 1.0.0 */ export const as = dual(2, as_(Functor)); /** * @category mapping * @since 1.0.0 */ export const flap = flap_(Functor); /** * Maps every value to the void constant value. * * @category mapping * @since 1.0.0 */ export const asUnit = asUnit_(Functor); // ------------------------------------------------------------------------------------- // apply in sequence // ------------------------------------------------------------------------------------- /** * @category instances * @since 1.0.0 */ export const ApplySeq = { ...Functor, ap: (fab, fa) => (use) => fab((ab) => fa((a) => use(ab(a)))), }; /** * Runs computations sequentially. * * @category instances * @since 1.0.0 */ export const ApplicativeSeq = { ...Pointed, ...ApplySeq, }; /** * @category apply * @since 1.0.0 */ export const apFirstSeq = apFirst_(ApplySeq); /** * @category apply * @since 1.0.0 */ export const apSecondSeq = apSecond_(ApplySeq); /** * @category sequencing * @since 1.0.0 */ export const sequenceTSeq = sequenceT_(ApplySeq); /** * @category sequencing * @since 1.0.0 */ export const sequenceSSeq = sequenceS_(ApplySeq); // ------------------------------------------------------------------------------------- // apply in parallel // ------------------------------------------------------------------------------------- /** * @category instances * @since 1.0.0 */ export const ApplyPar = { ...Functor, ap: (fab, fa) => (use) => () => { let ab = O.none; let a = O.none; let resolvedFa = O.none; let resolveFa = (value) => { resolvedFa = O.some(value); }; let resolvedFab = O.none; let resolveFab = (value) => { resolvedFab = O.some(value); }; const promiseFa = fa((x) => () => { if (O.isSome(resolvedFa)) { return Promise.resolve(resolvedFa.value); } if (O.isSome(ab)) { return use(ab.value(x))(); } return new Promise((resolve) => { a = O.some(x); resolveFa = resolve; }); })().then((ea) => { resolveFab(ea); return ea; }); const promiseFab = fab((f) => () => { if (O.isSome(resolvedFab)) { return Promise.resolve(resolvedFab.value); } if (O.isSome(a)) { return use(f(a.value))().then((ret) => { resolveFa(ret); return promiseFa.then((retFa) => pipe(retFa, E.apSecond(ret))); }); } return new Promise((resolve) => { ab = O.some(f); resolveFab = resolve; }); })().then((eab) => { resolveFa(eab); return eab; }); return Promise.all([promiseFab, promiseFa]).then(([eab]) => eab); }, }; /** * @category instances * @since 1.0.0 */ export const ApplicativePar = { ...Pointed, ...ApplyPar }; /** * @category apply * @since 1.0.0 */ export const ap = (fa) => (fab) => ApplyPar.ap(fab, fa); /** * @category apply * @since 1.0.0 */ export const apFirst = apFirst_(ApplyPar); /** * @category apply * @since 1.0.0 */ export const apSecond = apSecond_(ApplyPar); /** * @category sequencing * @since 1.0.0 */ export const sequenceT = sequenceT_(ApplyPar); /** * @category sequencing * @since 1.0.0 */ export const sequenceS = sequenceS_(ApplyPar); // ------------------------------------------------------------------------------------- // monad // ------------------------------------------------------------------------------------- /** * @category instances * @since 1.0.0 */ export const Chain = { ...ApplySeq, chain: (fa, f) => (use) => fa((a) => f(a)(use)), }; /** * @category instances * @since 1.0.0 */ export const Monad = { ...Pointed, ...Chain, }; /** * @category instances * @since 1.0.0 */ export const MonadIO = { ...Monad, fromIO, }; /** * @category instances * @since 1.0.0 */ export const MonadTask = { ...MonadIO, fromTask, }; /** * @category sequencing * @since 1.0.0 */ export const flatMap = (f) => (fa) => Chain.chain(fa, f); /** * Composes computations in sequence, using the return value of one computation to determine the next computation and * keeping only the result of the first. * * @category combinators * @since 1.0.0 */ export const tap = /*#__PURE__*/ dual(2, tap_(Chain)); /** * @category combinators * @since 1.0.0 */ export const tapIO = /*#__PURE__*/ dual(2, tapIO_(FromIO, Chain)); /** * @category combinators * @since 1.0.0 */ export const tapEither = /*#__PURE__*/ dual(2, tapEither_(FromEither, Chain)); /** * @category combinators * @since 1.0.0 */ export const tapTask = /*#__PURE__*/ dual(2, tapTask_(FromTask, Chain)); // ------------------------------------------------------------------------------------- // do notation // ------------------------------------------------------------------------------------- /** * @category do notation * @since 1.0.0 */ export const Do = of({}); /** * @category do notation * @since 1.0.0 */ export const bind = bind_(Chain); /** * @category do notation * @since 1.0.0 */ export const bindTo = bindTo_(Functor); const _let = let_(Functor); export { /** * @category do notation * @since 1.0.0 */ _let as let, }; /** * @category do notation * @since 1.0.0 */ export const apS = apS_(ApplyPar); /** * @category do notation * @since 1.0.0 */ export const apSSeq = apS_(ApplySeq); // ------------------------------------------------------------------------------------- // array utils // ------------------------------------------------------------------------------------- // In parallel /** * Equivalent to `ReadonlyNonEmptyArray#traverseWithIndex(ApplicativePar)`. * * @category traversing * @since 1.0.0 */ export const traverseReadonlyNonEmptyArrayWithIndex = RNEA.traverseWithIndex(ApplicativePar); /** * Equivalent to `ReadonlyArray#traverseWithIndex(ApplicativePar)`. * * @category traversing * @since 1.0.0 */ export const traverseReadonlyArrayWithIndex = RA.traverseWithIndex(ApplicativePar); /** * Equivalent to `ReadonlyArray#traverse(ApplicativePar)`. * * @category traversing * @since 1.0.0 */ export const traverseArray = RA.traverse(ApplicativePar); /** * Equivalent to `ReadonlyArray#sequence(ApplicativePar)`. * * @category traversing * @since 1.0.0 */ export const sequenceArray = RA.sequence(ApplicativePar); // In sequence /** * Equivalent to `ReadonlyNonEmptyArray#traverseWithIndex(ApplicativeSeq)`. * * @category traversing * @since 1.0.0 */ export const traverseSeqReadonlyNonEmptyArrayWithIndex = RNEA.traverseWithIndex(ApplicativeSeq); /** * Equivalent to `ReadonlyArray#traverseWithIndex(ApplicativeSeq)`. * * @category traversing * @since 1.0.0 */ export const traverseSeqReadonlyArrayWithIndex = RA.traverseWithIndex(ApplicativeSeq); /** * Equivalent to `ReadonlyArray#traverse(ApplicativeSeq)`. * * @category traversing * @since 1.0.0 */ export const traverseSeqArray = RA.traverse(ApplicativeSeq); /** * Equivalent to `ReadonlyArray#sequence(ApplicativeSeq)`. * * @category traversing * @since 1.0.0 */ export const sequenceSeqArray = RA.sequence(ApplicativeSeq);