lilit
Version:
[![Build status][tr-svg]][travis]
793 lines (706 loc) • 22.2 kB
text/typescript
import { asyncTee, asyncTeeN, forAwaitableIterator } from './common.ts';
import { ForOfAwaitable } from './common.ts';
// OPERATORS
export function map<A, B>(f: (x: A) => B) {
return async function*(xs: ForOfAwaitable<A>): AsyncIterableIterator<B> {
for await (const x of xs) yield f(x);
};
}
export function tap<X>(f: (x: X) => any) {
return async function*(xs: ForOfAwaitable<X>): AsyncIterableIterator<X> {
for await (const x of xs) {
f(x);
yield x;
}
};
}
export const inspect = tap;
export function forEach<X>(f: (x: X) => any) {
return async function(xs: ForOfAwaitable<X>): Promise<void> {
for await (const x of xs) f(x);
};
}
export const subscribe = forEach;
export function reduce<X, R>(f: (acc: R, x: X) => R, init: R) {
return async function(xs: ForOfAwaitable<X>): Promise<R> {
let res = init;
for await (const x of xs) {
res = f(res, x);
}
return res;
};
}
export function scan<X, R>(f: (acc: R, x: X) => R, init: R) {
return async function*(xs: ForOfAwaitable<X>): AsyncIterableIterator<R> {
let res = init;
for await (const x of xs) {
res = f(res, x);
yield res;
}
};
}
export const reducutions = scan;
export function some<X>(p: (x: X) => boolean) {
return async function(xs: ForOfAwaitable<X>): Promise<boolean> {
for await (const x of xs) {
if (p(x)) return true;
}
return false;
};
}
export function every<X>(p: (x: X) => boolean) {
return async function(xs: ForOfAwaitable<X>): Promise<boolean> {
for await (const x of xs) {
if (!p(x)) return false;
}
return true;
};
}
export function filter<X>(p: (x: X) => boolean) {
return async function*(xs: ForOfAwaitable<X>): AsyncIterableIterator<X> {
for await (const x of xs) {
if (p(x)) yield x;
}
};
}
export function partition<X>(p: (x: X) => boolean) {
return function(xs: ForOfAwaitable<X>): [AsyncIterableIterator<X>, AsyncIterableIterator<X>] {
const [xs1, xs2] = asyncTee(xs);
return [filter(p)(xs1), filter((x: X) => !p(x))(xs2)];
};
}
export function skip<X>(n: number) {
return async function*(xs: ForOfAwaitable<X>): AsyncIterableIterator<X> {
let i = 0;
for await (const x of xs) {
if (++i <= n) continue;
yield x;
}
};
}
export function take<X>(n: number) {
return async function*(xs: ForOfAwaitable<X>): AsyncIterableIterator<X> {
let i = 0;
for await (const x of xs) {
if (++i > n) break;
yield x;
}
};
}
// TODO: rename?
export function partitionAt<X>(n: number) {
return function(xs: ForOfAwaitable<X>): [AsyncIterableIterator<X>, AsyncIterableIterator<X>] {
const [xs1, xs2] = asyncTee(xs);
return [take<X>(n)(xs1), skip<X>(n)(xs2)];
};
}
export const splitAt = partitionAt;
export function skipWhile<X>(f: (x: X) => boolean) {
return async function*(xs: ForOfAwaitable<X>): AsyncIterableIterator<X> {
const it = forAwaitableIterator(xs);
let first: X;
for await (const x of it) {
first = x;
if (!f(x)) break;
}
yield first;
for await (const x of it) yield x;
};
}
export function takeWhile<X>(f: (x: X) => boolean) {
return async function*(xs: ForOfAwaitable<X>): AsyncIterableIterator<X> {
for await (const x of xs) {
if (f(x)) yield x;
else break;
}
};
}
export function partitionWhile<X>(f: (x: X) => boolean) {
return function(xs: ForOfAwaitable<X>): [AsyncIterableIterator<X>, AsyncIterableIterator<X>] {
const [xs1, xs2] = asyncTee(xs);
return [takeWhile<X>(f)(xs1), skipWhile<X>(f)(xs2)];
};
}
export function find<X>(p: (x: X) => boolean) {
return async function(xs: ForOfAwaitable<X>): Promise<X | null> {
for await (const x of xs) {
if (p(x)) return x;
}
return null;
};
}
export function findIndex<X>(p: (x: X) => boolean) {
return async function(xs: ForOfAwaitable<X>): Promise<number> {
let i = 0;
for await (const x of xs) {
if (p(x)) return i;
i++;
}
return -1;
};
}
export function pluck<X>(key: string | number) {
return async function*(xs: ForOfAwaitable<Object>): AsyncIterableIterator<X | null> {
for await (const x of xs) yield x[key];
};
}
// like pluck, but accepts an iterable of keys
export function select<X>(keys: Array<string | number>) {
return async function*(xs: ForOfAwaitable<Object>): AsyncIterableIterator<X | null> {
for await (const x of xs) {
let r = x;
for (const k of keys) {
r = r != null ? r[k] : undefined;
}
yield r as (X | null);
}
};
}
export function unzip2<X, Y>() {
return function(xs: ForOfAwaitable<[X, Y]>): [AsyncIterableIterator<X>, AsyncIterableIterator<Y>] {
const [xs1, xs2] = asyncTee(xs);
return [pluck<X>(0)(xs1), pluck<Y>(1)(xs2)];
};
}
export function unzip3<X, Y, Z>() {
return function(
xs: ForOfAwaitable<[X, Y, Z]>,
): [AsyncIterableIterator<X>, AsyncIterableIterator<Y>, AsyncIterableIterator<Z>] {
const [xs1, xs2, xs3] = asyncTeeN(xs, 3);
return [pluck<X>(0)(xs1), pluck<Y>(1)(xs2), pluck<Z>(2)(xs3)];
};
}
export function unzip(n: number = 2) {
return function(xs: ForOfAwaitable<{}[]>): AsyncIterableIterator<{}>[] {
const xss = asyncTeeN(xs, n);
return xss.map((xs, i) => pluck(i)(xs));
};
}
export function groupBy<X, K>(f: (x: X) => K) {
return async function(xs: ForOfAwaitable<X>): Promise<Map<K, X[]>> {
const res = new Map<K, X[]>();
for await (const x of xs) {
const key = f(x);
if (!res.has(key)) res.set(key, []);
res.get(key).push(x);
}
return res;
};
}
export function groupByKey<X>(key: string | number) {
return groupBy<X, string | number>((x: X) => x[key]);
}
export function mapKeys<KA, KB, V>(f: (k: KA) => KB) {
return async function*(xs: ForOfAwaitable<[KA, V]>): AsyncIterableIterator<[KB, V]> {
for await (const [k, v] of xs) yield [f(k), v];
};
}
export function mapValues<VA, VB, K>(f: (v: VA) => VB) {
return async function*(xs: ForOfAwaitable<[K, VA]>): AsyncIterableIterator<[K, VB]> {
for await (const [k, v] of xs) yield [k, f(v)];
};
}
export function pairwise<X>() {
return async function*(xs: ForOfAwaitable<X>): AsyncIterableIterator<[X, X]> {
const it = forAwaitableIterator(xs);
let prev = (await it.next()).value;
for await (const x of it) {
yield [prev, x];
prev = x;
}
};
}
export function length() {
return async function(xs: ForOfAwaitable<{}>): Promise<number> {
let c = 0;
for await (const _ of xs) c++;
return c;
};
}
export function min() {
return async function(xs: ForOfAwaitable<number>): Promise<number> {
let res = Number.POSITIVE_INFINITY;
for await (const x of xs) {
if (x < res) res = x;
}
return res;
};
}
export function max() {
return async function(xs: ForOfAwaitable<number>): Promise<number> {
let res = Number.NEGATIVE_INFINITY;
for await (const x of xs) {
if (x > res) res = x;
}
return res;
};
}
export function minMax() {
return async function(xs: ForOfAwaitable<number>): Promise<[number, number]> {
let min = Number.POSITIVE_INFINITY;
let max = Number.NEGATIVE_INFINITY;
for await (const x of xs) {
if (x < min) min = x;
if (x > max) max = x;
}
return [min, max];
};
}
export function minBy<X>(cf: (a: X, b: X) => number) {
return async function(xs: ForOfAwaitable<X>): Promise<X | null> {
const it = forAwaitableIterator(xs);
const { done, value } = await it.next();
if (done) return null;
let res = value;
for await (const x of it) if (cf(x, res) < 0) res = x;
return res;
};
}
export function maxBy<X>(cf: (a: X, b: X) => number) {
return async function(xs: ForOfAwaitable<X>): Promise<X | null> {
const it = forAwaitableIterator(xs);
const { done, value } = await it.next();
if (done) return null;
let res = value;
for await (const x of it) if (cf(x, res) > 0) res = x;
return res;
};
}
export function minMaxBy<X>(cf: (a: X, b: X) => number) {
return async function(xs: ForOfAwaitable<X>): Promise<[X | null, X | null]> {
const it = forAwaitableIterator(xs);
const { done, value } = await it.next();
if (done) return [null, null];
let min = value;
let max = value;
for await (const x of it) {
if (cf(x, min) < 0) min = x;
if (cf(x, max) > 0) max = x;
}
return [min, max];
};
}
export function minByScan<X>(cf: (a: X, b: X) => number) {
return async function*(xs: ForOfAwaitable<X>): AsyncIterableIterator<X | null> {
const it = forAwaitableIterator(xs);
const { done, value } = await it.next();
if (done) yield null;
let res = value;
for await (const x of it) {
if (cf(x, res) < 0) res = x;
yield res;
}
};
}
export function maxByScan<X>(cf: (a: X, b: X) => number) {
return async function*(xs: ForOfAwaitable<X>): AsyncIterableIterator<X | null> {
const it = forAwaitableIterator(xs);
const { done, value } = await it.next();
if (done) yield null;
let res = value;
for await (const x of it) {
if (cf(x, res) > 0) res = x;
yield res;
}
};
}
export function sum(zero: number = 0) {
return async function(xs: ForOfAwaitable<number>): Promise<number> {
let res = zero;
for await (const x of xs) res += x;
return res;
};
}
export function replaceWhen<X, Y>(pf: (x: X) => boolean, ys: ForOfAwaitable<Y>) {
return async function*(xs: ForOfAwaitable<X>): AsyncIterableIterator<X | Y> {
for await (const [x, y] of zip2(xs, ys)) {
if (!pf(x)) yield x;
else yield y;
}
};
}
export function grouped<X>(n: number, step: number = n) {
return async function*(xs: ForOfAwaitable<X>): AsyncIterableIterator<X[]> {
let group = [];
for await (const x of xs) {
group.push(x);
if (group.length === n) {
yield [...group];
for (let i = 0; i < step; i++) group.shift();
}
}
};
}
export function startWith<X>(...as: X[]) {
return async function*(xs: ForOfAwaitable<X>): AsyncIterableIterator<X> {
for await (const a of as) yield a;
for await (const x of xs) yield x;
};
}
export function endWith<X>(...zs: X[]) {
return async function*(xs: ForOfAwaitable<X>): AsyncIterableIterator<X> {
for await (const x of xs) yield x;
for await (const z of zs) yield z;
};
}
export function sort<X>(cf: (a: X, b: X) => number) {
return async function*(xs: ForOfAwaitable<X>): AsyncIterableIterator<X> {
let arr = [];
for await (const x of xs) arr.push(x);
for (const x of arr.sort(cf)) yield x;
};
}
export function sortScan<X>(cf: (a: X, b: X) => number) {
return async function*(xs: ForOfAwaitable<X>): AsyncIterableIterator<X[]> {
let arr = [];
for await (const x of xs) {
arr.push(x);
yield [...arr.sort(cf)];
}
};
}
export function flatMap<A, B>(f: (x: A) => B) {
return async function*(xss: ForOfAwaitable<ForOfAwaitable<A>>): AsyncIterableIterator<B> {
for await (const xs of xss) for await (const x of xs) yield await f(x);
};
}
export function distinctUntilChanged<X>(comp: (a: X, b: X) => boolean = (a, b) => a === b) {
return async function*(xs: ForOfAwaitable<X>): AsyncIterableIterator<X> {
const it = forAwaitableIterator(xs);
let { done, value: initial } = await it.next();
if (done) return;
yield initial;
for await (const x of it) if (!comp(x, initial)) yield (initial = x);
};
}
export function unique<X>(comp: (a: X, b: X) => boolean = (a, b) => a === b) {
return async function*(xs: ForOfAwaitable<X>): AsyncIterableIterator<X> {
const arr = [];
for await (const x of xs) arr.push(x);
const unq = arr.filter((x, i, self) => self.findIndex(y => comp(x, y)) === i);
for (const u of unq) yield u;
};
}
export function uniqueSorted<X>(comp: (a: X, b: X) => boolean = (a, b) => a === b) {
return async function*(xs: ForOfAwaitable<X>): AsyncIterableIterator<X> {
const arr = [];
for await (const x of xs) arr.push(x);
arr.sort();
for await (const x of distinctUntilChanged(comp)(arr)) yield x;
};
}
// CONSTRUCTORS
export async function* range(start = 0, end = Number.MAX_SAFE_INTEGER, step = 1): AsyncIterableIterator<number> {
for (let i = start; end > start ? i < end : i > end; i += step) yield i;
}
// TODO: rename to `entries`?
export async function* enumerate<X>(xs: ForOfAwaitable<X>): AsyncIterableIterator<[number, X]> {
let i = 0;
for await (const x of xs) yield [i++, x];
}
export async function* concat<X>(...xss: ForOfAwaitable<X>[]): AsyncIterableIterator<X> {
for (const xs of xss) for await (const x of xs) yield x;
}
export const chain = concat;
export async function* zip2<X, Y>(xs: ForOfAwaitable<X>, ys: ForOfAwaitable<Y>): AsyncIterableIterator<[X, Y]> {
const xit = forAwaitableIterator(xs);
const yit = forAwaitableIterator(ys);
while (true) {
const [xr, yr] = await Promise.all([xit.next(), yit.next()]);
if (xr.done || yr.done) break;
yield [xr.value, yr.value];
}
}
export async function* zip3<X, Y, Z>(
xs: ForOfAwaitable<X>,
ys: ForOfAwaitable<Y>,
zs: ForOfAwaitable<Z>,
): AsyncIterableIterator<[X, Y, Z]> {
const xit = forAwaitableIterator(xs);
const yit = forAwaitableIterator(ys);
const zit = forAwaitableIterator(zs);
while (true) {
const [xr, yr, zr] = await Promise.all([xit.next(), yit.next(), zit.next()]);
if (xr.done || yr.done || zr.done) break;
yield [xr.value, yr.value, zr.value];
}
}
export async function* zip(...xss: ForOfAwaitable<{}>[]): AsyncIterableIterator<{}[]> {
const its = xss.map(forAwaitableIterator);
while (true) {
const rs = await Promise.all(its.map(it => it.next()));
if (rs.some(r => r.done)) break;
yield rs.map(r => r.value);
}
}
// TODO: rename? Is this how regular zip commonly works?
export async function* zipOuter(...xss: ForOfAwaitable<{}>[]): AsyncIterableIterator<{}[]> {
const its = xss.map(forAwaitableIterator);
while (true) {
const rs = await Promise.all(its.map(it => it.next()));
if (rs.every(r => r.done)) break;
yield rs.map(r => r.value);
}
}
export async function* product2<A, B>(as: ForOfAwaitable<A>, bs: ForOfAwaitable<B>): AsyncIterableIterator<[A, B]> {
// if (as === bs) [as, bs] = asyncTee(as);
let bs2: ForOfAwaitable<B>;
for await (const a of as) {
[bs, bs2] = asyncTee(bs);
for await (const b of bs2) {
yield [a, b];
}
}
}
export async function* product3<A, B, C>(
as: ForOfAwaitable<A>,
bs: ForOfAwaitable<B>,
cs: ForOfAwaitable<C>,
): AsyncIterableIterator<[A, B, C]> {
// if (as === bs) [as, bs] = asyncTee(as);
// if (as === cs) [as, cs] = asyncTee(as);
// if (bs === cs) [bs, cs] = asyncTee(bs);
let bs2: ForOfAwaitable<B>;
let cs2: ForOfAwaitable<C>;
for await (const a of as) {
[bs, bs2] = asyncTee(bs);
for await (const b of bs2) {
[cs, cs2] = asyncTee(cs);
for await (const c of cs2) {
yield [a, b, c];
}
}
}
}
// TODO: generalize to n parameters
export async function* product(xs: ForOfAwaitable<{}>, ...xss: ForOfAwaitable<{}>[]): AsyncIterableIterator<{}[]> {
throw new Error('Not implemented');
}
// TODO: other name (look at python itertools?)
// TODO: fix implementation
export async function* combinations2<X>(xs: ForOfAwaitable<X>): AsyncIterableIterator<[X, X]> {
let [as, bs] = asyncTee(xs);
let bs2: ForOfAwaitable<X>;
let i = 1;
for await (const a of as) {
[bs, bs2] = asyncTee(bs);
for await (const b of skip<X>(i++)(bs2)) {
yield [a, b];
}
}
}
export async function* combinations3<X>(xs: ForOfAwaitable<X>): AsyncIterableIterator<[X, X, X]> {
throw Error('Not implemented');
// let [as, bs, cs] = asyncTeeN(xs, 3);
// let bs2: ForOfAwaitable<X>;
// let cs2: ForOfAwaitable<X>;
// let i = 1;
// let j = 2;
// for await (const a of as) {
// [bs, bs2] = asyncTee(bs);
// for await (const b of skip<X>(i++)(bs2)) {
// [cs, cs2] = asyncTee(cs);
// for await (const c of skip<X>(j++)(cs2)) {
// yield [a, b, c];
// }
// }
// }
}
export async function* combinations(xs: ForOfAwaitable<{}>, r: number = 2): AsyncIterableIterator<{}[]> {
throw Error('Not implemented');
}
export async function* combinationsWithReplacement2<X>(xs: ForOfAwaitable<X>): AsyncIterableIterator<[X, X]> {
let [as, bs] = asyncTee(xs);
let bs2: ForOfAwaitable<X>;
let i = 0;
for await (const a of as) {
[bs, bs2] = asyncTee(bs);
for await (const b of skip<X>(i++)(bs2)) {
yield [a, b];
}
}
}
export async function* combinationsWithReplacement3<X>(xs: ForOfAwaitable<X>): AsyncIterableIterator<[X, X, X]> {
throw Error('Not implemented');
// let [as, bs, cs] = asyncTeeN(xs, 3);
// let bs2: ForOfAwaitable<X>;
// let cs2: ForOfAwaitable<X>;
// let i = 0;
// let j = 0;
// for await (const a of as) {
// [bs, bs2] = asyncTee(bs);
// for await (const b of skip<X>(i++)(bs2)) {
// [cs, cs2] = asyncTee(cs);
// for await (const c of skip<X>(j++)(cs2)) {
// yield [a, b, c];
// }
// }
// }
}
export async function* combinationsWithReplacement(xs: ForOfAwaitable<{}>, r: number = 2): AsyncIterableIterator<{}[]> {
throw Error('Not implemented');
}
export async function* permutations2<X>(xs: ForOfAwaitable<X>): AsyncIterableIterator<[X, X]> {
throw Error('Not implemented');
}
export async function* permutations3<X>(xs: ForOfAwaitable<X>): AsyncIterableIterator<[X, X, X]> {
throw Error('Not implemented');
}
export async function* permutations(xs: ForOfAwaitable<{}>, r: number = 2): AsyncIterableIterator<{}[]> {
throw Error('Not implemented');
}
export async function* constantly<X>(value: X): AsyncIterableIterator<X> {
while (true) yield value;
}
export async function* cycle<X>(xs: ForOfAwaitable<X>): AsyncIterableIterator<X> {
let xs2: ForOfAwaitable<X>;
while (true) {
[xs, xs2] = asyncTee(xs);
for await (const x of xs2) yield x;
}
}
export async function* repeat<X>(xs: ForOfAwaitable<X>, n: number): AsyncIterableIterator<X> {
let xs2: ForOfAwaitable<X>;
for (let i = 0; i < n; i++) {
[xs, xs2] = asyncTee(xs);
for await (const x of xs2) yield x;
}
}
export async function* interleave2<X, Y>(xs: ForOfAwaitable<X>, ys: ForOfAwaitable<Y>): AsyncIterableIterator<X | Y> {
const itx = forAwaitableIterator(xs);
const ity = forAwaitableIterator(ys);
while (true) {
const rx = await itx.next();
if (rx.done) break;
else yield rx.value;
const ry = await ity.next();
if (ry.done) break;
else yield ry.value;
}
}
export async function* interleave3<X, Y, Z>(
xs: ForOfAwaitable<X>,
ys: ForOfAwaitable<Y>,
zs: ForOfAwaitable<Z>,
): AsyncIterableIterator<X | Y | Z> {
const itx = forAwaitableIterator(xs);
const ity = forAwaitableIterator(ys);
const itz = forAwaitableIterator(zs);
while (true) {
const rx = await itx.next();
if (rx.done) break;
else yield rx.value;
const ry = await ity.next();
if (ry.done) break;
else yield ry.value;
const rz = await itz.next();
if (rz.done) break;
else yield rz.value;
}
}
export async function* interleave(...xss: ForOfAwaitable<{}>[]): AsyncIterableIterator<{}> {
const its = xss.map(forAwaitableIterator);
// Throwback to the 90s
outerloop: while (true) {
for (const it of its) {
const { done, value } = await it.next();
// Yup, this just happened
if (done) break outerloop;
else yield value;
}
}
}
// https://github.com/Microsoft/TypeScript/issues/17718#issuecomment-402931751
export async function pipe<T1>(x: T1): Promise<T1>;
export async function pipe<T1, T2>(x: T1, f1: (x: T1) => T2): Promise<T2>;
export async function pipe<T1, T2, T3>(x: T1, f1: (x: T1) => T2, f2: (x: T2) => T3): Promise<T3>;
export async function pipe<T1, T2, T3, T4>(x: T1, f1: (x: T1) => T2, f2: (x: T2) => T3, f3: (x: T3) => T4): Promise<T4>;
export async function pipe<T1, T2, T3, T4, T5>(
x: T1,
f1: (x: T1) => T2,
f2: (x: T2) => T3,
f3: (x: T3) => T4,
f4: (x: T4) => T5,
): Promise<T5>;
export async function pipe<T1, T2, T3, T4, T5, T6>(
x: T1,
f1: (x: T1) => T2,
f2: (x: T2) => T3,
f3: (x: T3) => T4,
f4: (x: T4) => T5,
f5: (x: T5) => T6,
): Promise<T6>;
export async function pipe<T1, T2, T3, T4, T5, T6, T7>(
x: T1,
f1: (x: T1) => T2,
f2: (x: T2) => T3,
f3: (x: T3) => T4,
f4: (x: T4) => T5,
f5: (x: T5) => T6,
f6: (x: T6) => T7,
): Promise<T7>;
export async function pipe<T1, T2, T3, T4, T5, T6, T7, T8>(
x: T1,
f1: (x: T1) => T2,
f2: (x: T2) => T3,
f3: (x: T3) => T4,
f4: (x: T4) => T5,
f5: (x: T5) => T6,
f6: (x: T6) => T7,
f7: (x: T7) => T8,
): Promise<T8>;
export async function pipe<T1, T2, T3, T4, T5, T6, T7, T8, T9>(
x: T1,
f1: (x: T1) => T2,
f2: (x: T2) => T3,
f3: (x: T3) => T4,
f4: (x: T4) => T5,
f5: (x: T5) => T6,
f6: (x: T6) => T7,
f7: (x: T7) => T8,
f8: (x: T8) => T9,
): Promise<T9>;
export async function pipe<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(
x: T1,
f1: (x: T1) => T2,
f2: (x: T2) => T3,
f3: (x: T3) => T4,
f4: (x: T4) => T5,
f5: (x: T5) => T6,
f6: (x: T6) => T7,
f7: (x: T7) => T8,
f8: (x: T8) => T9,
f9: (x: T9) => T10,
): Promise<T10>;
export async function pipe<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>(
x: T1,
f1: (x: T1) => T2,
f2: (x: T2) => T3,
f3: (x: T3) => T4,
f4: (x: T4) => T5,
f5: (x: T5) => T6,
f6: (x: T6) => T7,
f7: (x: T7) => T8,
f8: (x: T8) => T9,
f9: (x: T9) => T10,
f10: (x: T10) => T11,
): Promise<T11>;
export async function pipe<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>(
x: T1,
f1: (x: T1) => T2,
f2: (x: T2) => T3,
f3: (x: T3) => T4,
f4: (x: T4) => T5,
f5: (x: T5) => T6,
f6: (x: T6) => T7,
f7: (x: T7) => T8,
f8: (x: T8) => T9,
f9: (x: T9) => T10,
f10: (x: T10) => T11,
f11: (x: T11) => T12,
): Promise<T12>;
export async function pipe(x: any, ...fs: Function[]): Promise<any> {
let res = await x;
for (const f of fs) res = await f(res);
return res;
}