@jsoldi/hkt
Version:
Higher kinded types for typescript and a few utility monads.
80 lines • 2.98 kB
JavaScript
import { monad } from "../classes/monad.js";
import { pipe } from "../core/utils.js";
/** An error thrown when a task is aborted. */
export class AbortError extends Error {
constructor(msg) {
super(msg ?? 'Task was aborted');
this.name = 'AbortError';
}
}
/** The task module, providing functions to work with `Task` instances, which are promise-returning functions. */
export const task = (() => {
return pipe((() => {
const fun = (asyncLike) => (...args) => {
const promiseFun = (asyncLike) => (...args) => {
return typeof asyncLike === 'function' ? promiseFun(asyncLike(...args))() : asyncLike;
};
return () => promiseFun(asyncLike)(...args);
};
const unit = (a) => () => Promise.resolve(a);
const bind = (fa, f) => () => fa().then(a => fun(f)(a)());
const flatMap = (f) => (fa) => bind(fa, f);
const map = (fa, f) => () => fa().then(f);
return {
...monad({ unit, bind, flatMap, map }),
fun
};
})(), base => {
const delay = (ms) => () => new Promise(resolve => setTimeout(resolve, ms));
const promises = (fa) => fa.map(t => t());
const all = (fa) => () => Promise.all(promises(fa));
const race = (fa) => () => Promise.race(promises(fa));
const any = (fa) => () => Promise.any(promises(fa));
const run = (fa) => fa();
const runFree = (t) => async () => {
while (t.right)
t = await t.value();
return t.value;
};
const memo = (f) => {
let memo = undefined;
return () => {
if (memo === undefined)
memo = f();
return memo;
};
};
const abortable = (signal) => (fa) => () => new Promise((resolve, reject) => {
const doAbort = () => reject(new AbortError());
if (signal.aborted)
return doAbort();
signal.addEventListener('abort', doAbort);
fa().then(resolve, reject).finally(() => signal.removeEventListener('abort', doAbort));
});
const expirable = (ms) => (ta) => {
return () => {
const controller = new AbortController();
const id = setTimeout(() => controller.abort(), ms);
return abortable(controller.signal)(ta)().finally(() => clearTimeout(id));
};
};
const _catch = (f) => (fa) => () => fa().catch(e => f(e)());
const _finally = (f) => (fa) => () => fa().finally(f);
return {
...base,
run,
runFree,
delay,
promises,
all,
race,
any,
memo,
abortable,
expirable,
catch: _catch,
finally: _finally,
};
});
})();
//# sourceMappingURL=task.js.map