I've sometimes found myself wanting an asychronous version of unfold in Javascript: a function that would take a value, then apply an async function to it to get another value, and repeat on this value until some condition applies, producing an array (/ stream / iterator) of values.
E.g.
const res = await asyncUnfold(x=>Promise.resolve(x+1), x => x<6, 2)
console.log(res) // [2,3,4,5]
(real examples would do meaningful async operations: e.g. making a repeated network call based on some seed value, and recording all results.)
Does anyone know of a good implementation of this? I can use an async generator or async while loop to do the work, but I'd rather not have to think about coding that each time I want a similar operation. Perhaps there's a good implementation on NPM already...
(see https://nabilhassein.github.io/blog/unfold/ and https://en.wikipedia.org/wiki/Anamorphism and https://raganwald.com/2016/11/30/anamorphisms-in-javascript.html for some background on unfold. Ramda has an implementation of unfold, but it doesn't seem to do async operations. P-iterator and Rubico have async array operations, but neither seem to include unfold).
EDIT: in some cases, and perhaps in general, it might be better to NOT include the initial (seed) value in the returned array: e.g.
const res = await asyncUnfoldExclusive(x=>Promise.resolve(x+1), x => x<6, 2)
console.log(res) // [3,4,5]
You can just take the implementation from the article you linked and slap async/await on it:
async function asyncUnfold(f, seed) { /*
^^^^^ */
var arr = [];
var state = seed;
var next;
while (next = await f(state)) {
// ^^^^^
state = next[1];
arr.push(next[0]);
}
return arr;
}
Or using the three-parameter style from your question,
async function asyncUnfold(step, pred, value) {
const res = [];
while (pred(value)) {
res.push(value);
value = await step(value);
}
return res;
}
or implemented in a recursive style
async function asyncUnfold(step, pred, value) {
return pred(value)
? [value, ...await asyncUnfold(step, pred, await step(value))]
: [];
}
Here is a functional style solution to support the example you have given:
const asyncUnfold = (next, predicate, start) =>
!predicate(start) ? Promise.resolve([])
: next(start).then(value => asyncUnfold(next, predicate, value))
.then(arr => [start, ...arr]);
asyncUnfold(x => Promise.resolve(x+1), x => x<6, 2).then(console.log); // [2,3,4,5]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With