From e24b742ab4e3a9079fa46b30ba47cb486d00d1a7 Mon Sep 17 00:00:00 2001 From: Vesa Karvonen Date: Sat, 17 Nov 2018 12:55:25 +0200 Subject: [PATCH] More support for asynchronous operations --- src/ext/infestines.js | 43 +++++++++ src/partial.lenses.js | 200 +++++++++++++++++++++++++++++++++++++----- test/tests.js | 115 ++++++++++++++++++++++++ test/type.js | 6 +- test/types.js | 120 ++++++++++++++++++++++++- 5 files changed, 457 insertions(+), 27 deletions(-) diff --git a/src/ext/infestines.js b/src/ext/infestines.js index 362b4141..07c60a94 100644 --- a/src/ext/infestines.js +++ b/src/ext/infestines.js @@ -36,3 +36,46 @@ export function isPrimitiveData(x) { } export const iterator = Symbol.iterator + +export const thenU = I.Async.chain +export const then = I.curry(thenU) + +export const thenIdentityU = I.IdentityAsync.chain + +const EMPTY = 'empty' +const CONCAT = 'concat' + +export function Monoid(concat, empty) { + if (!I.isInstanceOfU(Monoid, this)) return I.freeze(new Monoid(concat, empty)) + this[CONCAT] = concat + this[EMPTY] = empty +} + +export const MonoidWith = (concat, empty) => Monoid(concat, I.always(empty)) + +export const MonoidAsyncOf = m => { + const concat = m[CONCAT] + return Monoid( + (l, r) => + I.isThenable(l) + ? thenU( + l => (I.isThenable(r) ? thenU(r => concat(l, r), r) : concat(l, r)), + l + ) + : I.isThenable(r) + ? thenU(r => concat(l, r), r) + : concat(l, r), + m[EMPTY] + ) +} + +export const ProductMonoid = MonoidWith(multiplyU, 1) + +export const SumMonoid = MonoidWith(addU, 0) + +export const ConstantWith = (ap, empty) => + I.Applicative(I.sndU, I.always(empty), ap) + +export const ConstantOf = m => ConstantWith(m[CONCAT], m[EMPTY]()) + +export const ConstantAsyncOf = I.pipe2U(MonoidAsyncOf, ConstantOf) diff --git a/src/partial.lenses.js b/src/partial.lenses.js index ae353afe..9edf79c9 100644 --- a/src/partial.lenses.js +++ b/src/partial.lenses.js @@ -5,6 +5,7 @@ import * as C from './contract' // const id = x => x +const ignore = () => {} const setName = process.env.NODE_ENV === 'production' ? x => x : I.defineNameU @@ -57,6 +58,7 @@ const cpair = xs => x => [x, xs] const pairPartial = k => v => (void 0 !== k && void 0 !== v ? [k, v] : void 0) const unto = c => x => (void 0 !== x ? x : c) +const unto1 = unto(1) const unto0 = unto(0) const toTrue = I.always(true) @@ -167,6 +169,25 @@ const copyToFrom = (process.env.NODE_ENV === 'production' // +const selectAsync = (step, at, s, x, y) => { + const cont = v => (void 0 !== v ? v : next()) + const next = () => { + if (void 0 !== (s = step(s, x, y))) { + const vP = at(s, x, y) + return I.isThenable(vP) ? I.thenU(cont, vP) : cont(vP) + } + } + return next() +} + +const arrayStep = (i, xs) => (++i < xs[I.LENGTH] ? i : void 0) +const arrayAt = (i, xs, xi2v) => xi2v(xs[i], i) + +const selectInArrayLikeAsync = (xi2v, xs) => + selectAsync(arrayStep, arrayAt, -1, xs, xi2v) + +// + function selectInArrayLike(xi2v, xs) { for (let i = 0, n = xs[I.LENGTH]; i < n; ++i) { const v = xi2v(xs[i], i) @@ -176,11 +197,14 @@ function selectInArrayLike(xi2v, xs) { // -const ConstantWith = (ap, empty) => I.Applicative(I.sndU, I.always(empty), ap) +const JoinMonoid = d => + I.MonoidWith((x, y) => (void 0 !== x ? (void 0 !== y ? x + d + y : x) : y)) -const ConstantOf = ({concat, empty}) => ConstantWith(concat, empty()) +const Product = I.ConstantOf(I.ProductMonoid) +const ProductAsync = I.ConstantAsyncOf(I.ProductMonoid) -const Sum = ConstantWith(I.addU, 0) +const Sum = I.ConstantOf(I.SumMonoid) +const SumAsync = I.ConstantAsyncOf(I.SumMonoid) const mumBy = ord => I.curry(function mumBy(xi2y, t, s) { @@ -408,12 +432,6 @@ function composed(oi0, os) { } } -const disperseU = function disperse(traversal, values, data) { - if (!seemsArrayLike(values)) values = '' - let i = 0 - return modifyU(traversal, () => values[i++], data) -} - const setU = (process.env.NODE_ENV === 'production' ? id : C.par(0, C.ef(reqOptic)))(function set(o, x, s) { @@ -453,6 +471,16 @@ const modifyU = (process.env.NODE_ENV === 'production' const modifyAsyncU = (o, f, s) => I.resolve(toFunction(o)(s, void 0, I.IdentityAsync, f)) +const disperseWith = modifyU => + function disperse(traversal, values, data) { + if (!seemsArrayLike(values)) values = '' + let i = 0 + return modifyU(traversal, () => values[i++], data) + } + +const disperseU = disperseWith(modifyU) +const disperseAsyncU = disperseWith(modifyAsyncU) + const getAsU = (process.env.NODE_ENV === 'production' ? id : C.par(1, C.ef(reqOptic)))(function getAs(xi2y, l, s) { @@ -634,7 +662,7 @@ const branchOr1LevelIdentity = (process.env.NODE_ENV === 'production' return written ? (same && xO === x ? x : r) : x }) -const branchOr1Level = (otherwise, k2o) => (x, _i, A, xi2yA) => { +const branchOr1Level = (otherwise, k2o, ks) => (x, _i, A, xi2yA) => { const xO = x instanceof Object ? toObject(x) : I.object0 if (I.Identity === A) { @@ -650,6 +678,34 @@ const branchOr1Level = (otherwise, k2o) => (x, _i, A, xi2yA) => { if (void 0 !== y) return y } } + } else if (SelectAsync === A) { + return I.thenIdentityU( + v => + void 0 !== v + ? v + : selectAsync( + arrayStep, + (i, xks, k2o) => { + const k = xks[i] + if (void 0 === k2o[k]) { + return otherwise(xO[k], k, A, xi2yA) + } + }, + -1, + I.keys(xO), + k2o + ), + selectAsync( + arrayStep, + (i, ks) => { + const k = ks[i] + return k2o[k](xO[k], k, A, xi2yA) + }, + -1, + ks, + k2o + ) + ) } else { const {map, ap, of} = A let xsA = of(cpair) @@ -671,11 +727,13 @@ const branchOr1Level = (otherwise, k2o) => (x, _i, A, xi2yA) => { function branchOrU(otherwise, template) { const k2o = I.create(null) + const ks = [] for (const k in template) { + ks.push(k) const v = template[k] k2o[k] = I.isObject(v) ? branchOrU(otherwise, v) : toFunction(v) } - return branchOr1Level(otherwise, k2o) + return branchOr1Level(otherwise, k2o, ks) } const replaced = (inn, out, x) => (I.acyclicEqualsU(x, inn) ? out : x) @@ -938,6 +996,8 @@ const elemsI = (xs, _i, A, xi2yA) => ? mapPartialIndexU(xi2yA, xs, void 0) : A === Select ? selectInArrayLike(xi2yA, xs) + : A === SelectAsync + ? selectInArrayLikeAsync(xi2yA, xs) : traversePartialIndex(A, xi2yA, xs, void 0) // @@ -1369,7 +1429,13 @@ export const seemsArrayLike = x => export {Identity, IdentityAsync} from './ext/infestines' -export const Select = ConstantWith((l, r) => (void 0 !== l ? l : r)) +const apSelect = (l, r) => (void 0 !== l ? l : r) + +export const Select = I.ConstantWith(apSelect) + +export const SelectAsync = I.ConstantWith(function apSelectAsync(f, x) { + return I.isThenable(f) ? I.thenU(f => apSelect(f, x), f) : apSelect(f, x) +}) export const toFunction = (process.env.NODE_ENV === 'production' ? id @@ -1392,8 +1458,14 @@ export const assign = I.curry(function assign(o, x, s) { return setU([o, assignTo], x, s) }) +export const assignAsync = I.curry(function assignAsync(o, x, s) { + return modifyAsyncU([o, assignTo], I.always(x), s) +}) + export const disperse = I.curry(disperseU) +export const disperseAsync = I.curry(disperseAsyncU) + export const modify = I.curry(modifyU) export const modifyAsync = I.curry(modifyAsyncU) @@ -1402,8 +1474,16 @@ export const remove = I.curry(function remove(o, s) { return setU(o, void 0, s) }) +export const removeAsync = I.curry(function removeAsync(t, s) { + return modifyAsyncU(t, I.always(), s) +}) + export const set = I.curry(setU) +export const setAsync = I.curry(function setAsync(t, v, s) { + return modifyAsyncU(t, I.always(v), s) +}) + export const traverse = I.curry(traverseU) // Nesting @@ -1564,6 +1644,11 @@ export const reIx = o => { export const skipIx = setName(tieIx(I.sndU), 'skipIx') +// Async + +export const awaitIt = (x, i, F, xi2yF) => + I.isThenable(x) ? I.thenU(x => xi2yF(x, i), x) : xi2yF(x, i) + // Debugging export function getLog(l, s) { @@ -1646,6 +1731,8 @@ export const elemsTotal = (xs, i, A, xi2yA) => ? mapPartialIndexU(xi2yA, xs, mapPartialIndexU) : A === Select ? selectInArrayLike(xi2yA, xs) + : A === SelectAsync + ? selectInArrayLikeAsync(xi2yA, xs) : traversePartialIndex(A, xi2yA, xs, traversePartialIndex) : A.of(xs) @@ -1700,7 +1787,10 @@ export function matches(re) { } } -export const values = setName(branchOr1Level(identity, I.protoless0), 'values') +export const values = setName( + branchOr1Level(identity, I.protoless0, I.array0), + 'values' +) export function children(x, i, C, xi2yC) { return I.isArray(x) @@ -1794,6 +1884,22 @@ export const collectAs = (process.env.NODE_ENV === 'production' export const collect = collectAs(id) +export const collectAsAsync = I.curry((xi2y, t, s) => { + const results = [] + const pushDefined = y => { + if (void 0 !== y) results.push(y) + } + const r = toFunction(t)(s, void 0, SelectAsync, (x, i) => { + const y = xi2y(x, i) + return I.isThenable(y) ? I.thenU(pushDefined, y) : pushDefined(y) + }) + return I.isThenable(r) + ? I.thenU(() => freezeInDev(results), r) + : I.resolve(freezeInDev(results)) +}) + +export const collectAsync = collectAsAsync(id) + export const collectTotalAs = (process.env.NODE_ENV === 'production' ? I.curry : C.res(I.freeze))(function collectTotalAs(xi2y, t, s) { @@ -1810,10 +1916,14 @@ export const collectTotalAs = (process.env.NODE_ENV === 'production' export const collectTotal = collectTotalAs(id) -export const concatAs = mkTraverse(id, ConstantOf) +export const concatAs = mkTraverse(id, I.ConstantOf) export const concat = concatAs(id) +export const concatAsAsync = mkTraverse(I.resolve, I.ConstantAsyncOf) + +export const concatAsync = concatAsAsync(id) + export const countIf = I.curry(function countIf(p, t, s) { return traverseU(Sum, (x, i) => (p(x, i) ? 1 : 0), t, s) }) @@ -1872,6 +1982,15 @@ export const forEach = I.curry(function forEach(f, t, s) { ) }) +export const forEachAsync = I.curry(function forEachAsync(f, t, s) { + return I.resolve( + toFunction(t)(s, void 0, SelectAsync, (x, i) => { + const r = f(x, i) + if (I.isThenable(r)) return I.thenU(ignore, r) + }) + ) +}) + export const forEachWith = I.curry(function forEachWith(newC, ef, t, s) { const c = newC() getAsU( @@ -1890,6 +2009,12 @@ export function get(l, s) { export const getAs = I.curry(getAsU) +export const getAsAsync = I.curry(function getAsAsync(f, t, s) { + return I.resolve(toFunction(t)(s, void 0, SelectAsync, f)) +}) + +export const getAsync = getAsAsync(id) + export const isDefined = I.curry(function isDefined(t, s) { return void 0 !== getAsU(id, t, s) }) @@ -1905,15 +2030,18 @@ export const joinAs = mkTraverse( : C.par( 0, C.ef(reqString('`join` and `joinAs` expect a string delimiter')) - ))(function joinAs(d) { - return ConstantWith((x, y) => - void 0 !== x ? (void 0 !== y ? x + d + y : x) : y - ) - }) + ))(setName(I.pipe2U(JoinMonoid, I.ConstantOf), 'joinAs')) ) export const join = joinAs(id) +export const joinAsAsync = mkTraverse( + I.pipe2U(I.resolve, I.then(toStringPartial)), + setName(I.pipe2U(JoinMonoid, I.ConstantAsyncOf), 'joinAsAsync') +) + +export const joinAsync = joinAsAsync(id) + export const maximumBy = mumBy(I.gtU) export const maximum = maximumBy(id) @@ -1937,6 +2065,28 @@ export const meanAs = I.curry(function meanAs(xi2y, t, s) { export const mean = meanAs(id) +export const meanAsAsync = I.curry(function meanAsAsync(xi2y, t, s) { + let sum = 0 + let num = 0 + const accumDefined = y => { + if (void 0 !== y) { + num += 1 + sum += y + } + } + return I.resolve( + I.thenU( + () => sum / num, + toFunction(t)(s, void 0, SelectAsync, (x, i) => { + const y = xi2y(x, i) + return I.isThenable(y) ? I.thenU(accumDefined, y) : accumDefined(y) + }) + ) + ) +}) + +export const meanAsync = meanAsAsync(id) + export const minimumBy = mumBy(I.ltU) export const minimum = minimumBy(id) @@ -1953,9 +2103,13 @@ export const none = I.curry(function none(xi2b, t, s) { export const or = any(id) -export const productAs = traverse(ConstantWith(I.multiplyU, 1)) +export const productAs = traverse(Product) -export const product = productAs(unto(1)) +export const product = productAs(unto1) + +export const productAsAsync = I.pipe2U(traverse(ProductAsync), I.resolve) + +export const productAsync = productAsAsync(unto1) export const select = process.env.NODE_ENV === 'production' @@ -1983,6 +2137,10 @@ export const sumAs = traverse(Sum) export const sum = sumAs(unto0) +export const sumAsAsync = I.pipe2U(traverse(SumAsync), I.resolve) + +export const sumAsync = sumAsAsync(unto0) + // Creating new lenses export const foldTraversalLens = I.curry(function foldTraversalLens( diff --git a/test/tests.js b/test/tests.js index 41e1ef21..196592d6 100644 --- a/test/tests.js +++ b/test/tests.js @@ -237,11 +237,13 @@ describe('arities', () => { array: 1, arrays: 1, assign: 3, + assignAsync: 3, assignOp: 1, assignTo: 4, attemptEveryDown: 1, attemptEveryUp: 1, attemptSomeDown: 1, + awaitIt: 4, branch: 1, branchOr: 2, branches: 0, @@ -252,12 +254,16 @@ describe('arities', () => { choose: 1, collect: 2, collectAs: 3, + collectAsAsync: 3, + collectAsync: 2, collectTotal: 2, collectTotalAs: 3, complement: 4, compose: 0, concat: 3, concatAs: 4, + concatAsAsync: 4, + concatAsync: 3, cond: 0, condOf: 1, conjugate: 2, @@ -271,6 +277,7 @@ describe('arities', () => { define: 1, disjoint: 1, disperse: 3, + disperseAsync: 3, divide: 1, dropPrefix: 1, dropSuffix: 1, @@ -288,12 +295,15 @@ describe('arities', () => { foldl: 4, foldr: 4, forEach: 3, + forEachAsync: 3, forEachWith: 4, fromFantasy: 1, fromFantasyApplicative: 1, fromFantasyMonad: 1, get: 2, getAs: 3, + getAsAsync: 3, + getAsync: 2, getInverse: 2, getLog: 2, getter: 1, @@ -310,6 +320,8 @@ describe('arities', () => { iterate: 1, join: 3, joinAs: 4, + joinAsAsync: 4, + joinAsync: 3, joinIx: 1, json: 1, keyed: 4, @@ -329,6 +341,8 @@ describe('arities', () => { maximumBy: 3, mean: 2, meanAs: 3, + meanAsAsync: 3, + meanAsync: 2, minimum: 2, minimumBy: 3, modify: 3, @@ -355,6 +369,8 @@ describe('arities', () => { prependTo: 4, product: 2, productAs: 3, + productAsAsync: 3, + productAsync: 2, prop: 1, props: 0, propsExcept: 0, @@ -364,6 +380,7 @@ describe('arities', () => { reIx: 1, removable: 0, remove: 2, + removeAsync: 2, removeOp: 4, replace: 2, replaces: 2, @@ -377,6 +394,7 @@ describe('arities', () => { selectAs: 3, seq: 0, set: 3, + setAsync: 3, setIx: 1, setOp: 1, setter: 1, @@ -390,6 +408,8 @@ describe('arities', () => { suffix: 1, sum: 2, sumAs: 3, + sumAsAsync: 3, + sumAsync: 2, tieIx: 2, toFunction: 1, transform: 2, @@ -3016,6 +3036,101 @@ describe('ix', () => { }) describe('async', () => { + testEq( + () => + L.productAsAsync(x => (x < 3 ? later(0, x) : x), L.elems, [3, 1, 4, 1]), + 12 + ) + + testEq( + () => L.sumAsAsync(x => (x < 3 ? later(0, x) : x), L.elems, [3, 1, 4, 1]), + 9 + ) + + testEq( + () => + L.meanAsAsync(x => (x < 3 ? later(0, x) : x), L.elems, [ + 3, + 1, + undefined, + 4, + 1 + ]), + 2.25 + ) + + testEq( + async () => { + const rs = [] + await L.forEachAsync( + (x, i) => (x < 3 ? I.resolve : I.id)(rs.push([x, i])), + L.elems, + [3, 1, 4] + ) + return rs + }, + [[3, 0], [1, 1], [4, 2]] + ) + + testEq(() => L.assignAsync(L.awaitIt, {x: 1}, {y: 2}), {x: 1, y: 2}) + + testEq( + () => L.removeAsync([L.awaitIt, L.elems, 'x'], I.resolve([{x: 1, y: 2}])), + [{y: 2}] + ) + + testEq( + () => L.setAsync([L.awaitIt, L.elems, 'x'], 3, I.resolve([{x: 1, y: 2}])), + [{x: 3, y: 2}] + ) + + testEq(() => L.joinAsAsync(later(0), '-', L.elems, ['3', '1', '4']), '3-1-4') + + testEq( + () => + L.concatAsAsync(x => (x < 3 ? later(0, x) : x), Sum, L.elems, [3, 1, 4]), + 8 + ) + + testEq( + () => L.collectAsync(L.branches('x', 'a', 'y', 'z'), {x: 3, y: 1, z: 4}), + [3, 1, 4] + ) + + testEq( + () => + X.collectAsAsync( + x => (x < 3 ? later(0, x) : x), + X.branches('x', 'a', 'y', 'z'), + { + x: 3, + y: 1, + z: 4 + } + ), + [3, 1, 4] + ) + + testEq( + () => + L.getAsync( + [ + L.elems, + L.branchOr([], {x: [], y: []}), + later(2), + L.awaitIt, + L.when(x => 4 < x) + ], + [ + {x: 3, y: 1, z: 4}, + {x: 1, y: 5, z: 9, w: 2}, + {x: 6, y: 5}, + {x: 3, y: 5} + ] + ), + 5 + ) + testEq(() => L.modifyAsync(L.elems, x => later(5, -x), [3, 1, 4]), [ -3, -1, diff --git a/test/type.js b/test/type.js index 4b1a2cc1..32d1fb91 100644 --- a/test/type.js +++ b/test/type.js @@ -37,11 +37,11 @@ export const instanceOf = c => fromPredicate(x => x instanceof c) const isFreezable = x => I.isArray(x) || - (x instanceof Object && - !(x instanceof Promise || x instanceof Int8Array || x instanceof Error)) + (x instanceof Object && !(x instanceof Int8Array || x instanceof Error)) const isFrozen = x => !isFreezable(x) || Object.isFrozen(x) const isDeepFrozen = x => !isFreezable(x) || + isThenable(x) || (Object.isFrozen(x) && !Object.getOwnPropertyNames(x).find(k => !isDeepFrozen(x[k]))) @@ -52,6 +52,8 @@ export const deepFrozen = fromPredicate(isDeepFrozen) export const deepFreeze = x => isFrozen(x) ? x + : isThenable(x) + ? x.then(deepFreeze) : (Object.getOwnPropertyNames(x).forEach(k => deepFreeze(x[k])), Object.freeze(x)) diff --git a/test/types.js b/test/types.js index e836af56..288402ee 100644 --- a/test/types.js +++ b/test/types.js @@ -75,6 +75,8 @@ export const IdentityAsync = T_monad export const Select = T_applicative +export const SelectAsync = T_applicative + export const toFunction = T.fn( [T_optic], T_opticFnOf(T.or(T_monad, T_applicative, T_functor)) @@ -86,14 +88,38 @@ export const assign = T.fn( [T_optic, T.instanceOf(Object), T_maybeDataI], T_maybeDataO ) +export const assignAsync = T.fn( + [T_optic, T.instanceOf(Object), T_maybeDataI], + T.thenable(T_maybeDataO) +) + export const disperse = T.fn([T_optic, T.any, T_maybeDataI], T_maybeDataO) +export const disperseAsync = T.fn( + [T_optic, T.any, T_maybeDataI], + T.thenable(T_maybeDataO) +) + export const modify = T.fn( [T_optic, T.fn([T_maybeDataO, T_index], T_maybeDataI), T_maybeDataI], T_maybeDataO ) -export const modifyAsync = modify +export const modifyAsync = T.fn( + [T_optic, T.fn([T_maybeDataO, T_index], T_maybeDataI), T_maybeDataI], + T.thenable(T_maybeDataO) +) + export const remove = T.fn([T_optic, T_maybeDataI], T_maybeDataO) +export const removeAsync = T.fn( + [T_optic, T_maybeDataI], + T.thenable(T_maybeDataO) +) + export const set = T.fn([T_optic, T_maybeDataI, T_maybeDataI], T_maybeDataO) +export const setAsync = T.fn( + [T_optic, T_maybeDataI, T_maybeDataI], + T.thenable(T_maybeDataO) +) + export const traverse = T.fn( [ T.or(T_monad, T_applicative, T_functor), @@ -143,6 +169,10 @@ export const setIx = T.fn([T_index], T_optic) export const skipIx = T.fn([T_optic], T_optic) export const tieIx = T.fn([T.fn([T_index, T_index], T_index), T_optic], T_optic) +// Async + +export const awaitIt = T_optic + // Debugging export const getLog = T.fn([T_traversal, T_maybeDataI], T_maybeDataO) @@ -151,7 +181,10 @@ export const log = T.fnVarN(0, T.string, T_optic) // Operations on transforms export const transform = T.fn([T_optic, T_maybeDataI], T_maybeDataO) -export const transformAsync = transform +export const transformAsync = T.fn( + [T_optic, T_maybeDataI], + T.thenable(T_maybeDataO) +) // Sequencing @@ -219,6 +252,19 @@ export const collectAs = T.fn( T.array(T.def) ) +export const collectAsync = T.fn( + [T_traversal, T_maybeDataI], + T.thenable(T.array(T.def)) +) +export const collectAsAsync = T.fn( + [ + T.fn([T_maybeDataO, T_index], T.or(T.thenable(T.any), T.any)), + T_traversal, + T_maybeDataI + ], + T.thenable(T.array(T.def)) +) + export const collectTotal = T.fn([T_traversal, T_maybeDataI], T.array(T.any)) export const collectTotalAs = T.fn( [T.fn([T_maybeDataO, T_index], T.any), T_traversal, T_maybeDataI], @@ -231,6 +277,15 @@ export const concatAs = T.fn( T.any ) +export const concatAsync = T.fn( + [T_monoid, T_traversal, T_maybeDataI], + T.thenable(T.any) +) +export const concatAsAsync = T.fn( + [T.fn([T_maybeDataO, T_index], T.any), T_monoid, T_traversal, T_maybeDataI], + T.thenable(T.any) +) + export const countIf = T.fn( [T.fn([T_maybeDataO, T_index], T.any), T_traversal, T_maybeDataI], T.number @@ -258,6 +313,10 @@ export const forEach = T.fn( [T.fn([T_maybeDataO, T_index], T.any), T_traversal, T_maybeDataI], T.undef ) +export const forEachAsync = T.fn( + [T.fn([T_maybeDataO, T_index], T.any), T_traversal, T_maybeDataI], + T.thenable(T.undef) +) export const forEachWith = T.fn( [ @@ -270,15 +329,24 @@ export const forEachWith = T.fn( ) export const get = T.fn([T_traversal, T_maybeDataI], T_maybeDataO) - export const getAs = T.fn( [T.fn([T_maybeDataO, T_index], T.any), T_traversal, T_maybeDataI], T.any ) +export const getAsync = T.fn( + [T_traversal, T_maybeDataI], + T.thenable(T_maybeDataO) +) +export const getAsAsync = T.fn( + [T.fn([T_maybeDataO, T_index], T.any), T_traversal, T_maybeDataI], + T.thenable(T.any) +) + export const isDefined = T.fn([T_traversal, T_maybeDataI], T.boolean) export const isEmpty = T.fn([T_traversal, T_maybeDataI], T.boolean) +export const join = T.fn([T.string, T_traversal, T_maybeDataI], T.string) export const joinAs = T.fn( [ T.fn([T_maybeDataO, T_index], T.or(T.string, T.undef)), @@ -289,7 +357,22 @@ export const joinAs = T.fn( T.string ) -export const join = T.fn([T.string, T_traversal, T_maybeDataI], T.string) +export const joinAsync = T.fn( + [T.string, T_traversal, T_maybeDataI], + T.thenable(T.string) +) +export const joinAsAsync = T.fn( + [ + T.fn( + [T_maybeDataO, T_index], + T.or(T.string, T.undef, T.thenable(T.or(T.string, T.undef))) + ), + T.string, + T_traversal, + T_maybeDataI + ], + T.thenable(T.string) +) export const maximumBy = T.fn([T_lens, T_traversal, T_maybeDataI], T.any) export const maximum = T.fn([T_traversal, T_maybeDataI], T.any) @@ -304,6 +387,19 @@ export const meanAs = T.fn( T.number ) +export const meanAsync = T.fn([T_traversal, T_maybeDataI], T.thenable(T.number)) +export const meanAsAsync = T.fn( + [ + T.fn( + [T_maybeDataO, T_index], + T.or(T.number, T.undef, T.thenable(T.or(T.number, T.undef))) + ), + T_traversal, + T_maybeDataI + ], + T.thenable(T.number) +) + export const minimumBy = maximumBy export const minimum = maximum @@ -317,9 +413,25 @@ export const productAs = T.fn( ) export const product = count +export const productAsAsync = T.fn( + [ + T.fn([T_maybeDataO, T_index], T.or(T.number, T.thenable(T.number))), + T_traversal, + T_maybeDataI + ], + T.thenable(T.number) +) +export const productAsync = T.fn( + [T_traversal, T_maybeDataI], + T.thenable(T.number) +) + export const sumAs = productAs export const sum = product +export const sumAsAsync = productAsAsync +export const sumAsync = productAsync + export const select = T.fn([T_traversal, T_maybeDataI], T.any) export const selectAs = T.fn( [T.fn([T_maybeDataO, T_index], T.any), T_traversal, T_maybeDataI],