Skip to content

Commit

Permalink
More support for asynchronous operations
Browse files Browse the repository at this point in the history
  • Loading branch information
polytypic committed Nov 17, 2018
1 parent 603b3f3 commit 9732d00
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 4 deletions.
81 changes: 77 additions & 4 deletions src/partial.lenses.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,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)
Expand Down Expand Up @@ -634,7 +653,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) {
Expand All @@ -650,6 +669,34 @@ const branchOr1Level = (otherwise, k2o) => (x, _i, A, xi2yA) => {
if (void 0 !== y) return y
}
}
} else if (SelectAsync === A) {
return I.IdentityAsync.chain(
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)
Expand All @@ -671,11 +718,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)
Expand Down Expand Up @@ -938,6 +987,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)

//
Expand Down Expand Up @@ -1369,7 +1420,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 = ConstantWith(apSelect)

export const SelectAsync = 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
Expand Down Expand Up @@ -1564,6 +1621,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) {
Expand Down Expand Up @@ -1646,6 +1708,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)

Expand Down Expand Up @@ -1700,7 +1764,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)
Expand Down Expand Up @@ -1890,6 +1957,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)
})
Expand Down
12 changes: 12 additions & 0 deletions test/tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ describe('arities', () => {
attemptEveryDown: 1,
attemptEveryUp: 1,
attemptSomeDown: 1,
awaitIt: 4,
branch: 1,
branchOr: 2,
branches: 0,
Expand Down Expand Up @@ -294,6 +295,8 @@ describe('arities', () => {
fromFantasyMonad: 1,
get: 2,
getAs: 3,
getAsAsync: 3,
getAsync: 2,
getInverse: 2,
getLog: 2,
getter: 1,
Expand Down Expand Up @@ -2996,6 +2999,15 @@ describe('ix', () => {
})

describe('async', () => {
testEq(
() =>
L.getAsync(
[L.elems, later(2), L.awaitIt, L.when(x => 3 < x)],
[3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
),
4
)

testEq(() => L.modifyAsync(L.elems, x => later(5, -x), [3, 1, 4]), [
-3,
-1,
Expand Down
10 changes: 10 additions & 0 deletions test/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -143,6 +145,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)
Expand Down Expand Up @@ -271,11 +277,15 @@ export const forEachWith = T.fn(

export const get = T.fn([T_traversal, T_maybeDataI], T_maybeDataO)

export const getAsync = get

export const getAs = T.fn(
[T.fn([T_maybeDataO, T_index], T.any), T_traversal, T_maybeDataI],
T.any
)

export const getAsAsync = getAs

export const isDefined = T.fn([T_traversal, T_maybeDataI], T.boolean)
export const isEmpty = T.fn([T_traversal, T_maybeDataI], T.boolean)

Expand Down

0 comments on commit 9732d00

Please sign in to comment.