Last active
June 23, 2017 19:56
-
-
Save lubien/13112df46a3603552e3f198900a9d4fd to your computer and use it in GitHub Desktop.
Proof of concept that you can map multiple functions with only one iteration in JavaScript using iterators (like in Python). Run https://repl.it/Izou/2
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* imap lazily maps an interable. | |
* @param fn Map function | |
* @param iterableOrIterator Either an iterable or an iterator | |
* | |
* It works by always returning a new iterator so that | |
* you can chain other imaps without loopin once more | |
* over the same array! | |
* | |
* Since iterables are returned, to start the real mapping | |
* you should do [...it] or use the function `list` I've made. | |
*/ | |
const imap = (fn, iterableOrIterator) => ({ | |
[Symbol.iterator]: () => { | |
// if it has a next method | |
const it = iterableOrIterator.next | |
// is an iterator | |
? iterableOrIterator | |
// otherwise it's an iterable, we need an iterator | |
: iterableOrIterator[Symbol.iterator]() | |
/* | |
* Now that we have an iterable, we can | |
* create our own iterable over it! | |
*/ | |
return { // this is our iterable | |
next() { | |
/* | |
* Get the next value of the iterable passed | |
* to us in the second parameter. | |
* | |
* If an array was passed like this: | |
* `imap(fn, [1, 2, 3])` | |
* `it.next` will will pass 1 then 2 then 3. | |
* Then we return fn(1) then fn(2) then fn(3). | |
* | |
* If we do a nested imap call like this: | |
* `imap(outerFn, imap(innerFn, [1, 2, 3])) | |
* | |
* 1. First our inner imap will catch and do just like I said above: | |
* receive 1 => return innerFn(1) then | |
* receive 2 => return innerFn(2) then | |
* receive 3 => return innerFn(3) end | |
* 2. Once each time we receive the inner imap we chain: | |
* receive innerFn(1) => return outerFn(innerFn(1)) then | |
* receive innerFn(2) => return outerFn(innerFn(2)) then | |
* receive innerFn(3) => return outerFn(innerFn(3)) end | |
* | |
*/ | |
// receive the inner value (just like I said above) | |
const {done, value} = it.next() | |
return { | |
done, // if the inner is done, the outer is done too | |
value: done ? value : fn(value) // if we are done, don't run fn | |
} | |
} | |
} | |
} | |
}) | |
const double = x => 2 * x | |
const square = x => x * x | |
const list = it => [...it] | |
list( | |
imap(square, | |
imap(double,[1, 2, 3, 4]))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment