I have been reading about map
, reduce
and filter
a lot because of how much they are used in react and FP in general. If we write something like:
let myArr = [1,2,3,4,5,6,7,8,9]
let sumOfDoubleOfOddNumbers = myArr.filter(num => num % 2)
.map(num => num * 2)
.reduce((acc, currVal) => acc + currVal, 0);
3 different loops are run.
I've read about Java 8 streams as well and know that they use what is called a monad, ie, the computations are stored first. They are performed once only in one iteration. For example,
Stream.of("d2", "a2", "b1", "b3", "c")
.map(s -> {
System.out.println("map: " + s);
return s.toUpperCase();
})
.filter(s -> {
System.out.println("filter: " + s);
return s.startsWith("A");
})
.forEach(s -> System.out.println("forEach: " + s));
// map: d2
// filter: D2
// map: a2
// filter: A2
// forEach: A2
// map: b1
// filter: B1
// map: b3
// filter: B3
// map: c
// filter: C
PS: Java code is taken from: http://winterbe.com/posts/2014/07/31/java8-stream-tutorial-examples/
There are many other languages that use this same method. Is there a way to do it the same way in JS as well?
This is an exact clone of your Java code. Unlike Bergi's solution, no need to modify global prototypes.
Actually, the chaining functionality could be decoupled from specific iterators to provide a generic framework:
Now, you can throw arbitrary generators into this, both predefined and ad-hoc ones, for example:
Um, no, that's not what Monad means.
Yes, you can use iterators. Check this implementation or that one (and for the monad methods, here).
In production code, you probably should use static functions instead of putting custom methods on the builtin iterator prototype.
You can achieve this using piping, i dunno if this makes it too complicated, but by using piping you can call
Array.reduce
on the pipe and it performs the same behaviour on each iteration.I took the pipe function from here
Here is a polyfill of the pipe reduce and an example if you want to use it for more dynamic purposes
Array.prototype.map and Array.prototype.filter creates new arrays from the previous one. Array.prototype.reduce applies a function against an accumulator and each element in the array (from left to right) to reduce it to a single value.
Therefore, neither of them allow lazy evaluation.
You can achieve laziness by reducing your multiples loops into one:
Another way could be handling lazy evaluations by yourself in a custom object as follows. Next snippet is an example redefining
filter
andmap
:However, you can check libraries like lazy.js which provides a lazy engine under the hood using iterators.