@jsoldi/hkt
Version:
Higher kinded types for typescript and a few utility monads.
165 lines • 4.77 kB
JavaScript
import { monad } from "../classes/monad.js";
import { fold } from "../classes/fold.js";
import { monadPlus } from "../classes/monadPlus.js";
import { monoid } from "../classes/monoid.js";
import { unfold } from "../classes/unfold.js";
import { task } from "./task.js";
/** The `Async` module, providing a set of functions to work with `Async` instances, which are functions that return an `AsyncGenerator` */
export const async = (() => {
const fun = (asyncLike) => (...args) => async function* () {
const getGen = async (al, ...as) => {
return await (typeof al !== 'function' ? al : getGen(al(...as)));
};
for await (const a of await getGen(asyncLike, ...args))
yield a;
};
const unit = a => async function* () { yield a; };
const bind = (fa, f) => async function* () {
for await (const a of fa()) {
for await (const b of fun(f)(a)())
yield b;
}
};
const flatMap = f => fa => bind(fa, f);
const map = (fa, f) => async function* () {
for await (const a of fa())
yield f(a);
};
const from = (asyncLike, ...args) => async function* () {
for await (const a of fun(asyncLike)(...args)())
yield a;
};
const flat = fa => async function* () {
for await (const a of fa())
yield* a();
};
const take = n => fa => async function* () {
for await (const a of fa()) {
if (n-- <= 0)
break;
yield a;
}
};
const toArray = (fa) => async () => {
const result = [];
for await (const a of fa())
result.push(a);
return result;
};
const filter = (pred) => (fa) => async function* () {
for await (const a of fa()) {
if (pred(a))
yield a;
}
};
const takeWhile = pred => fa => async function* () {
for await (const a of fa()) {
if (!await pred(a))
break;
yield a;
}
};
const skipWhile = pred => fa => async function* () {
let skip = true;
for await (const a of fa()) {
if (skip && !await pred(a))
skip = false;
if (!skip)
yield a;
}
};
const distinctBy = (key) => (fa) => async function* () {
const keys = new Set();
for await (const a of fa()) {
const k = key(a);
if (!keys.has(k)) {
keys.add(k);
yield a;
}
}
};
const distinct = (fa) => distinctBy(a => a)(fa);
const chunks = (size) => (fa) => async function* () {
let chunk = [];
for await (const a of fa()) {
chunk.push(a);
if (chunk.length === size) {
yield chunk;
chunk = [];
}
}
if (chunk.length > 0)
yield chunk;
};
const foldl = f => init => fa => async () => {
// Can't directly modify init because it'd modify it for all passed generators
let acc = init;
for await (const a of fa())
acc = f(acc, a);
return acc;
};
const empty = () => async function* () { };
const append = (fa, fb) => async function* () {
yield* fa();
yield* fb();
};
const _unfold = (f) => (b) => async function* () {
let next = await task.fun(f)(b)();
while (next.right) {
let a;
[a, b] = next.value;
yield a;
next = await task.fun(f)(b)();
}
};
const zip = (fa, fb) => async function* () {
const a = fa();
const b = fb();
while (true) {
const [aVal, bVal] = await Promise.all([a.next(), b.next()]);
if (aVal.done || bVal.done)
break;
yield [aVal.value, bVal.value];
}
};
const scalar = task;
return {
...fold({
map,
foldl,
scalar: scalar
}),
...unfold({
map,
unfold: _unfold,
scalar: scalar
}),
...monadPlus({
...monad({
map,
unit,
bind,
flatMap,
}),
...monoid({
empty,
append
}),
}),
scalar: scalar,
flatMap,
fun: fun,
from, // override MonadPlus implementation
take,
flat,
toArray,
filter,
takeWhile,
skipWhile,
distinctBy,
distinct,
chunks,
zip,
};
})();
//# sourceMappingURL=async.js.map