lean4-code-actions
Version:
Refactorings and snippets for Lean 4
203 lines (161 loc) • 9.16 kB
text/typescript
import { flatten, identity, last, range } from 'remeda'
import { Mapper } from './Mapper'
import { Modifier, ModifierP, ModifierV, ModifierVP } from './Modifier'
import { NonEmptyArray } from './NonEmptyArray'
import { ResultsAccumulator } from './ResultsAccumulator'
import { AlwaysTrueTypeGuard } from './typescript'
export async function mapAsync<In, Out, Args extends unknown[]>(values: In[], mapper: (value: In, ...args: Args) => Promise<Out>, ...args: Args) {
return Promise.all(values.map(value => mapper(value, ...args)))
}
export async function flatMapAsync<In, Out, Args extends unknown[]>(values: In[], mapper: (value: In, ...args: Args) => Promise<Out[]>, ...args: Args) {
const results = await mapAsync(values, mapper, ...args)
return flatten(results)
}
export async function mapIndexAsync<In, Out, Args extends unknown[]>(values: In[], mapper: (value: In, index: number, ...args: Args) => Promise<Out>, ...args: Args) {
return Promise.all(values.map((value, index) => mapper(value, index, ...args)))
}
export async function repeatAsync<Out, Args extends unknown[]>(count: number, mapper: (index: number, ...args: Args) => Promise<Out>, ...args: Args) {
return mapAsync(range(0, count), mapper, ...args)
}
export async function parMap<In, Out, Args extends unknown[]>(mapper: (value: In, ...args: Args) => Promise<Out>, values: In[], ...args: Args) {
return parallel(values.map(value => mapper(value, ...args)))
}
export async function parallelMap<In, Out, Args extends unknown[]>(values: In[], mapper: (value: In, ...args: Args) => Promise<Out>, ...args: Args) {
return parallel(values.map(value => mapper(value, ...args)))
}
export async function parallelMapGet<In, Out, Args extends unknown[]>(getter: (...args: Args) => Promise<In[]>, mapper: (value: In, ...args: Args) => Promise<Out>, ...args: Args) {
const values = await getter(...args)
return parallel(values.map(value => mapper(value, ...args)))
}
export async function parallelFlatMap<In, Out, Args extends unknown[]>(values: In[], mapper: (value: In, ...args: Args) => Promise<Out[]>, ...args: Args) {
const resultsArray = await Promise.all(values.map(value => mapper(value, ...args)))
return flatten(resultsArray)
}
export async function allFlat<In, Out, Args extends unknown[]>(values: Promise<In>[]) {
return flatten(await Promise.all(values))
}
export async function parallelMapIndex<In, Out, Args extends unknown[]>(values: In[], mapper: (value: In, index: number, ...args: Args) => Promise<Out>, ...args: Args) {
return parallel(values.map((value, index) => mapper(value, index, ...args)))
}
export async function parallelMapEvery<In, Out, Args extends unknown[]>(values: In[], mapper: (value: In, ...args: Args) => Promise<Out>, ...args: Args) {
const results = await parallelMap(values, mapper, ...args)
return results.every(identity)
}
export async function sequentialMap<In, Out, Args extends unknown[]>(values: In[], mapper: (value: In, ...args: Args) => Promise<Out>, ...args: Args) {
const results: Out[] = []
for (const value of values) {
results.push(await mapper(value, ...args))
}
return results
}
export const mapMaybeIntoAccumulator = <A, B>(mapper: Mapper<A, B | undefined>) => (values: A[]) => {
return values.reduce<ResultsAccumulator<B, A>>(function (accumulator, value) {
const result = mapper(value)
if (result) {
accumulator.successes.push(result)
} else {
accumulator.failures.push(value)
}
return accumulator
}, { successes: [], failures: [] })
}
export async function sequentialMapAsyncGen<In, Out, Args extends unknown[]>(values: AsyncGenerator<In>, mapper: (value: In, ...args: Args) => Promise<Out>, ...args: Args) {
const results: Out[] = []
for await (const value of values) {
results.push(await mapper(value, ...args))
}
return results
}
export async function parallelMapAsyncGen<In, Out, Args extends unknown[]>(values: AsyncGenerator<In>, mapper: (value: In, ...args: Args) => Promise<Out>, ...args: Args) {
const promises: Promise<Out>[] = []
for await (const value of values) {
promises.push(mapper(value, ...args))
}
return parallel(promises)
}
export const sequentialReduce = <Val>(modifiers: Modifier<Val>[]) => (value: Val) => {
return modifiers.reduce((value, modifier) => modifier(value), value)
}
export const chain = sequentialReduce
/**
* Map multiple modifiers over a single value
* V = Variadic
*/
export const sequentialReduceV = <Val, Args extends unknown[]>(modifiers: ModifierV<Val, Args>[], ...args: Args) => (value: Val) => {
return modifiers.reduce<Val>(($value, modifier) => {
return modifier($value, ...args)
}, value)
}
export const sequentialReducePushV = <Val, Args extends unknown[]>(modifiers: ModifierV<Val, Args>[], ...args: Args) => (value: Val) => {
const initial: NonEmptyArray<Val> = [value]
return modifiers.reduce<NonEmptyArray<Val>>((values: NonEmptyArray<Val>, modifier): NonEmptyArray<Val> => {
return [...values, modifier(last(values), ...args)]
}, initial)
}
export const sequentialReduceP = <Val>(modifiers: ModifierP<Val>[]) => async (value: Val) => {
return modifiers.reduce<Promise<Val>>(async ($value, modifier) => modifier(await $value), Promise.resolve(value))
}
export const pipeP = sequentialReduceP
export const sequentialReduceVP = <Val, Args extends unknown[]>(modifiers: ModifierVP<Val, Args>[], ...args: Args) => async (value: Val) => {
return modifiers.reduce<Promise<Val>>(async ($value, modifier) => {
return modifier(await $value, ...args)
}, Promise.resolve(value))
}
export const parSeqMapVP = (isDepthFirst: boolean) => <Val, Args extends unknown[]>(modifiers: ModifierVP<Val, Args>[], ...args: Args) => async (values: Val[]) => {
if (isDepthFirst) {
return sequentialMap(values, value => {
return sequentialReduceVP(modifiers, ...args)(value)
})
} else {
return sequentialMap(modifiers, modifier => {
return parallelMap(values, modifier, ...args)
})
}
}
export function parallel<A, M, K, N, P, D, G, C, O, L, Q, R>(promises: [Promise<A>, Promise<M>, Promise<K>, Promise<N>, Promise<P>, Promise<D>, Promise<G>, Promise<C>, Promise<O>, Promise<L>, Promise<Q>, Promise<R>]): Promise<[A, M, K, N, P, D, G, C, O, L, Q, R]>;
export function parallel<A, M, K, N, P, D, G, C, O, L, Q>(promises: [Promise<A>, Promise<M>, Promise<K>, Promise<N>, Promise<P>, Promise<D>, Promise<G>, Promise<C>, Promise<O>, Promise<L>, Promise<Q>]): Promise<[A, M, K, N, P, D, G, C, O, L, Q]>;
export function parallel<A, M, K, N, P, D, G, C, O, L>(promises: [Promise<A>, Promise<M>, Promise<K>, Promise<N>, Promise<P>, Promise<D>, Promise<G>, Promise<C>, Promise<O>, Promise<L>]): Promise<[A, M, K, N, P, D, G, C, O, L]>;
export function parallel<A, M, K, N, P, D, G, C, O>(promises: [Promise<A>, Promise<M>, Promise<K>, Promise<N>, Promise<P>, Promise<D>, Promise<G>, Promise<C>, Promise<O>]): Promise<[A, M, K, N, P, D, G, C, O]>;
export function parallel<A, M, K, N, P, D, G, C>(promises: [Promise<A>, Promise<M>, Promise<K>, Promise<N>, Promise<P>, Promise<D>, Promise<G>, Promise<C>]): Promise<[A, M, K, N, P, D, G, C]>;
export function parallel<A, M, K, N, P, D, G>(promises: [Promise<A>, Promise<M>, Promise<K>, Promise<N>, Promise<P>, Promise<D>, Promise<G>]): Promise<[A, M, K, N, P, D, G]>;
export function parallel<A, M, K, N, P, D>(promises: [Promise<A>, Promise<M>, Promise<K>, Promise<N>, Promise<P>, Promise<D>]): Promise<[A, M, K, N, P, D]>;
export function parallel<A, M, K, N, P>(promises: [Promise<A>, Promise<M>, Promise<K>, Promise<N>, Promise<P>]): Promise<[A, M, K, N, P]>;
export function parallel<A, M, K, N>(promises: [Promise<A>, Promise<M>, Promise<K>, Promise<N>]): Promise<[A, M, K, N]>;
export function parallel<A, M, K>(promises: [Promise<A>, Promise<M>, Promise<K>]): Promise<[A, M, K]>;
export function parallel<A, M>(promises: [Promise<A>, Promise<M>]): Promise<[A, M]>;
export function parallel<A>(promises: Promise<A>[]): Promise<A[]>;
export function parallel<A>(promises: Promise<A>[]): Promise<A[]> {
return Promise.allSettled(promises).then(rethrowAny)
}
export async function together<In, Out, Args extends unknown[]>(mappers: Array<(...args: Args) => Promise<Out>>, ...args: Args) {
return parallel(mappers.map(mapper => mapper(...args)))
}
export const rethrowErrors = <Err>(isError: (e: unknown) => e is Err) => <T>(results: PromiseSettledResult<T>[]) => {
const reasons = []
const values = []
for (const result of results) {
if (result.status === 'fulfilled') {
values.push(result.value)
} else {
if (isError(result.reason)) {
reasons.push(result.reason)
} else {
throw result.reason
}
}
}
if (reasons.length) {
throw flatten(reasons)
} else {
return values
}
}
export const rethrowAny = rethrowErrors(AlwaysTrueTypeGuard)
/**
* Await promise resolution in the background without blocking
*/
export const toBackground = <T>(promise: Promise<T>): void => {}
export const trap = <T>(promise: Promise<T>) => promise.catch((reason) => {
console.error(reason)
process.exit(1)
})