fp-ts-bracket
Version:
Bracket monad for fp-ts
421 lines (420 loc) • 10.1 kB
JavaScript
/**
* 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);