A collection of modules to easy deal with async iterables
- ai-event - Create an async iterable from an event emitter.
- ai-node - Node wrappers that returns async iterables and promises.
- ai-asfullfills - Return an aync iterable that emit a series promises as they fullfills
- ai-merge - Parallel merge of multiple async iterable.
- ai-filter - Filter over async iterables.
- ai-lines - Split an async iterable into lines.
- ai-map - Map over async iterables
- ai-sequence - Serial merge of multiple async iterable.
- ai-concat - Concat an async iterable into a promise
- ai-reduce - Reduce for async iterables.
- asynciterable - Async iterable class
- ai-from-stream - create an async iterable from a stream
- ai-log - Tap into an async iterable pipeline and log all chunks passing through
- ai-tap - Tap into an async iterable chain without affecting its value or state.
- is-async-iterable - Checks if a given object is async iterable.
All ai-fun modules follows a set of common conventions to improve interoperability within the modules.
- Currying
Currying is a common functional tecnique made popular by early functional languages. It allow to transform a function with arity > 1 in a unary function, by partially applying a set of argument to the function:
curriedFunction(a)(b)(c) === curriedFunction(a, b, c)
The advantage of using unary functions is that you can use it as arguments in higher order function:
const fetchUrl = curried((options, url) => {})
const docs = urlArr.map(fetchUrl({method: post}))
Within the javascript community, currying was popularized by libraries like ramda, but as explained by Dr. Axel Rauschmayer with his consuete deepness, it has some drawbacks.
Normal currying has another characteritic that greatly effect async functions: if you return a function in a async function, the caller get a promise of a function, making the caller site syntax ugly:
const fetchUrl = curried(async (options, url) => {})
const docs = urlArr.map(await fetchUrl({method: post}))
And things get worse if the function is an async generator:
const fetchUrl = await curried(async function * (options, url) => {})
const docs = urlArr.map((await fetchUrl({method: post}).next()).value)
So, ai-fun modules take a different approach: each function
has an with
method that partially apply it's arguments to the main
function, returning a unary function that accept the data
(or context, or main) parameter.
For example, to transform the reduce
function in unary
one:
const sum = reduce.with((acc, val) => acc + val, 0)
console.log(await sum([1, 2 ,3]))
// output 6
- Versioning
All ai-fun
modules started with version 1 and follows semantic versioning.
All major version bumping will happen at the same time for all of the modules.
- Iteration lazyness
for await vs map -> lower order iterables are iterated only when needed (optionally?)