Skip to content

Instantly share code, notes, and snippets.

@lubien
Last active June 23, 2017 19:56
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save lubien/13112df46a3603552e3f198900a9d4fd to your computer and use it in GitHub Desktop.
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
/*
* 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