Last active
April 28, 2016 22:53
-
-
Save benji6/ce2fd2c058ec5853f8d43cd6b94b3b10 to your computer and use it in GitHub Desktop.
Lazy iterables in JS
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
// imlazy show and tell | |
// utils | |
const compose = (...fns) => x => fns.reduceRight((acc, f) => f(acc), x) | |
const log = (x, ...xs) => (console.log(...[x + ':', '\n', ...xs, '\n'])) | |
// Generator expression | |
const oneTwoThreeGenerator = function * () { | |
yield 1 | |
yield 2 | |
yield 3 | |
} | |
// Invoke generator to create iterator | |
const oneTwoThreeIterator = oneTwoThreeGenerator() | |
// Iterator has next method which returns an Object | |
log( | |
'naturalNumbersIterator', | |
oneTwoThreeIterator.next(), | |
oneTwoThreeIterator.next(), | |
oneTwoThreeIterator.next(), | |
oneTwoThreeIterator.next(), | |
oneTwoThreeIterator.next() | |
) | |
log('oneTwoThreeIterator can only be iterated once', [...oneTwoThreeIterator]) | |
log('oneTwoThreeIterator newly generated', [...oneTwoThreeGenerator()]) | |
// Iterables | |
const oneTwoThreeIterable = {[Symbol.iterator]: oneTwoThreeGenerator} | |
log('oneTwoThreeIterable', [...oneTwoThreeIterable]) | |
log('oneTwoThreeIterable can be used multiple times', [...oneTwoThreeIterable]) | |
// range | |
const range = x => y => ({[Symbol.iterator]: function * () { | |
var n = x | |
if (n < y) while (n <= y) yield n++; else while (n >= y) yield n-- | |
}}) | |
const oneTwoThree = range(1)(3) | |
log('oneTwoThree created by range', [...oneTwoThree]) | |
const naturalNumbers = range(1)(Infinity) | |
const take = n => xs => ({[Symbol.iterator]: function * () { | |
let i = n | |
for (const x of xs) if (i-- === 0) return; else yield x | |
}}) | |
const take8 = take(8) | |
const take16 = take(16) | |
const first8NaturalNumbers = take8(naturalNumbers) | |
log('first8NaturalNumbers', [...first8NaturalNumbers]) | |
// first 8 even | |
const even = x => x % 2 === 0 | |
const filter = f => xs => ({[Symbol.iterator]: function * () { | |
for (const x of xs) if (f(x)) yield x | |
}}) | |
const filterEven = filter(even) | |
const first8Even = compose(take8, filterEven) | |
const first8EvenNaturalNumbers = first8Even(naturalNumbers) | |
log('first8EvenNaturalNumbers', [...first8EvenNaturalNumbers]) | |
// square | |
const squared = x => Math.pow(x, 2) | |
const map = f => xs => ({[Symbol.iterator]: function * () { | |
for (const x of xs) yield f(x) | |
}}) | |
const mapSquared = map(squared) | |
const first8EvenSquared = compose(mapSquared, first8Even) | |
log('first8EvenSquared', [...first8EvenSquared(naturalNumbers)]) | |
// less than | |
const lt = x => y => x > y | |
const takeWhile = f => xs => ({[Symbol.iterator]: function * () { | |
for (const x of xs) if (f(x)) yield x; else return | |
}}) | |
const takeWhileLt100 = takeWhile(lt(100)) | |
const evenSquaredLt100 = compose(takeWhileLt100, mapSquared, filterEven) | |
log('evenSquaredLt100', [...evenSquaredLt100(naturalNumbers)]) | |
// iterate | |
const double = x => 2 * x | |
const iterate = f => n => ({[Symbol.iterator]: function * () { | |
let x = n | |
yield x | |
while (true) yield x = f(x) | |
}}) | |
const iterateDouble = iterate(double) | |
const powersOf2Lt100 = takeWhileLt100(iterateDouble(2)) | |
log('powersOf2Lt100', [...powersOf2Lt100]) | |
const cycle = xs => ({[Symbol.iterator]: function * () { | |
while (true) yield* xs | |
}}) | |
const cycledPowersOf2Lt100 = cycle(powersOf2Lt100) | |
log('cycledPowersOf2Lt100', [...take16(cycledPowersOf2Lt100)]) | |
// fibonacci numbers | |
const fibonacciNumbers = ({[Symbol.iterator]: function * () { | |
let [x, y] = [1, 1] | |
while (true) { | |
yield x | |
;[x, y] = [y, x + y] | |
} | |
}}) | |
const first16FibonacciNumbers = take16(fibonacciNumbers) | |
log('first16FibonacciNumbers', [...first16FibonacciNumbers]) | |
const sum = xs => { | |
let total = 0 | |
for (const x of xs) total += x | |
return total | |
} | |
// sum | |
const sumFirst16FibonacciNumbers = sum(first16FibonacciNumbers) | |
log('sumFirst16FibonacciNumbers', sumFirst16FibonacciNumbers) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment