Skip to content

Instantly share code, notes, and snippets.

@matthiasak
Created March 25, 2016 19:54
Show Gist options
  • Save matthiasak/61d7c75901840f9d5c5c to your computer and use it in GitHub Desktop.
Save matthiasak/61d7c75901840f9d5c5c to your computer and use it in GitHub Desktop.
lazy sequences with generators
const flatten = (...a) =>
a.reduce((a,v) => {
if(v instanceof Array)
return [...a, ...flatten(...v)]
return a.concat(v)
}, [])
const iter = (...a) =>
wrap(function*(){
let b = flatten(a)
for(let i = 0, len = b.length; i<len; i++)
yield b[i]
})
const seq = (start=0, step=1, end) =>
wrap(function*(){
let i = start
while(end === undefined || i <= end){
yield i
i += step
}
})
const map = (gen, fn) =>
wrap(function*(){
for(let x of gen())
yield fn(x)
})
const filter = (gen, fn) =>
wrap(function*(){
for(let x of gen()) {
if(fn(x)) yield x
}
})
const take = (gen, num) =>
wrap(function*(){
let it = gen()
for(let i = 0; i<num; i++){
yield it.next().value
}
})
const value = gen => {
let x = []
for(let i of gen())
x.push(i)
return x
}
const wrap = gen => {
let g = function*(){
yield* gen()
}
return [value,map,filter,take].reduce((g,v) => {
g[fnName(v)] = v.bind(null, gen)
return g
}, g)
}
const fnName = fn =>
/^function (\w+)/.exec(fn+'')[1]
// create a generator that will step through each item (finite sequence)
let test = iter(1,2,3,4,5,6,7,8,9,10)
// log(test.value()) // accumulate the output with gen.value()
// log(value(test)) // ... or value(gen)
// ... or pass in an array, or any combination of values
let test2 = iter(1,2,3,[4,5,6],[[7,8,9,[10]]])
// log( test2.value() )
// lazily evaluate items with map/filter
// log( map(test, x => x * 2).value() )
// log( filter(test, x => x < 7).value() )
// chain lazy operations together
// ... via traditional passing
// log( value(take(filter(map(test, x=>2*x), x=>x>=10), 2)) )
// ... or via chaining
// log( test.map(x=>2*x).filter(x => x>10).value() )
// any operation can be told to do "just enough work", or all of it
// log( test.map(x => 2*x).filter(x => x<10).value() ) // calculates 4 results, returns array of 4
// log( test.map(x => 2*x).value().slice(0,4) ) // calculates 10 results, returns array of 4
// log( test.map(x => 2*x).filter(x => x<10).take(2).value() ) // only calculates 2 items
// you don't have to think in finite series / arrays
// log( seq(0, 2).map(x => Math.pow(x,2)).take(20).value() )
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment