A (somewhat) Universal approach to lazy sequence manipulation
Voltra
Posted on May 29, 2021
Fellow developers, how many times have you transformed
array.map(mapper).filter(predicate)
into
array.reduce(() => {
// Oh my god what do I do?
}, [])
just to avoid the added cost of N loops?
Most of those who, like me, absolutely love how expressive these methods can be, have found solutions in our respective languages:
- C++'s Range V3 or C++20 Ranges
- JavaScript's sequency
- Java 8's Stream API
- Kotlin's sequences
- Rust's iter
- Haskell's lists, sequences, etc...
That's all nice but they all have completely different interfaces, some harder to extend, etc...
What if, we could just have one way of doing things?
Let me introduce to you my attempt at a unified interface across programming languages: the Universal Couroutine Based Lazy Sequence Manipulation.
These fancy words mean that if your language has support for generators (or even better, coroutines!) then you will probably be able to implement this by adapting the pseudocode into your language of choice.
For those of us who are less fortunate and do not have access to generators or coroutines, there is a way to adapt this library to only use iterators instead.
Now, for the example:
const results = Stream.range(10)
.skip(5)
.take(100)
.map(x => 3*x - 5)
.filter(x => x % 4 === 0)
.map(x => x * 2)
.take(5)
.toArray();
console.log(results); // [32, 56, 80, 104, 128]
//// Strictly equivalent (in complexity) to
const results = [];
let count = 0;
for(const item of someMagicalIteratorRangeToSavePerformances(10, 115)){
if(count >= 5)
break;
const alpha = 3*item - 5;
if(alpha % 4 === 0){
const beta = alpha * 2;
results.push(beta);
count++;
}
}
console.log(results);
Easier to write, more readable, everything we love.
I aim to make it as usable as possible so writing a library is really simple and straightforward. Any contribution is appreciated.
Posted on May 29, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.