Last active
April 5, 2022 13:43
-
-
Save ryandabler/f4f19256183bec068bcb4e2094678f5f to your computer and use it in GitHub Desktop.
This file contains hidden or 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
// | |
// ----- Sequences ------------------------- | |
// | |
const range = (l, u = Infinity) => function* () { | |
while (true) { | |
if (l < u) { | |
yield l++; | |
continue; | |
} | |
return l; | |
} | |
}; | |
const repeat = (n) => function* () { | |
while (true) { | |
yield n; | |
} | |
}; | |
const fibonacci = () => function* () { | |
let f0 = 1; | |
let f1 = 1; | |
yield f0; | |
yield f1; | |
while (true) { | |
[f0, f1] = [f1, f0 + f1]; | |
yield f1; | |
} | |
}; | |
const primes = () => function* () { | |
const ps = []; | |
let n = 2; | |
while (true) { | |
const filteredPs = ps.filter( | |
x => x < Math.ceil(Math.sqrt(n)) | |
); | |
if (filteredPs.some(p => (n % p) === 0)) { | |
n++; | |
continue; | |
} | |
ps.push(n); | |
yield n++; | |
} | |
}; | |
// | |
// ----- Utility functions ------------------------- | |
// | |
const $SKIP = Symbol('skip'); | |
const take = (n) => (generator) => function* () { | |
while (n-- > 0) { | |
const { value, done } = generator.next(); | |
if (done) { | |
return value; | |
} | |
yield value; | |
} | |
}; | |
const takeWhile = (fn) => (generator) => function* () { | |
while (true) { | |
const { value, done } = generator.next(); | |
if (done && fn(value)) { | |
return value; | |
} | |
if (done && !fn(value)) { | |
return null; | |
} | |
if (fn(value)) { | |
yield value; | |
} | |
if (!fn(value)) { | |
return null; | |
} | |
} | |
}; | |
const drop = (n) => (generator) => function* () { | |
let counter = 0; | |
while (++counter <= n) { | |
const { done } = generator.next(); | |
if (done) { | |
return null; | |
} | |
} | |
while (true) { | |
const { value, done } = generator.next(); | |
if (done) { | |
return value; | |
} | |
yield value; | |
} | |
}; | |
const dropWhile = (fn) => (generator) => function* () { | |
while (true) { | |
const { value, done } = generator.next(); | |
if (done && fn(value)) { | |
return null; | |
} | |
if (done && !fn(value)) { | |
return value; | |
} | |
if (fn(value)) { | |
continue; | |
} | |
yield value; | |
} | |
}; | |
const map = (fn) => (generator) => function* () { | |
while (true) { | |
const { value, done } = generator.next(); | |
if (done) { | |
return fn(value); | |
} | |
yield fn(value); | |
} | |
}; | |
const filter = (fn) => (generator) => function* () { | |
while (true) { | |
const { value, done } = generator.next(); | |
if (done && fn(value)) { | |
return value; | |
} | |
if (done && !fn(value)) { | |
return $SKIP; | |
} | |
if (!fn(value)) { | |
continue; | |
} | |
yield value; | |
} | |
}; | |
// | |
// ----- Lazy list ------------------------- | |
// | |
class LazyList { | |
#generator; | |
#generatedValues = []; | |
#done = false; | |
constructor(generatorFn) { | |
this.#generator = generatorFn(); | |
} | |
#next() { | |
const { value, done } = this.#generator.next(); | |
if (done) { | |
this.#done = true; | |
} | |
if (value !== $SKIP) { | |
this.#generatedValues.push(value); | |
} | |
} | |
#asGenerator() { | |
function* toGenerator() { | |
let cursor = 0; | |
while (true) { | |
if (!Reflect.has(this.#generatedValues, cursor)) { | |
this.#next(); | |
} | |
if (this.#done) { | |
return this.#generatedValues[cursor++]; | |
} | |
yield this.#generatedValues[cursor++]; | |
} | |
} | |
return toGenerator.apply(this); | |
} | |
get(n) { | |
while (this.#generatedValues.length <= n && !this.#done) { | |
this.#next(); | |
} | |
return this.#generatedValues[n]; | |
} | |
take(n) { | |
const generator = take(n)(this.#asGenerator()); | |
return new LazyList(generator); | |
} | |
takeWhile(fn) { | |
const generator = takeWhile(fn)(this.#asGenerator()); | |
return new LazyList(generator); | |
} | |
drop(n) { | |
const generator = drop(n)(this.#asGenerator()); | |
return new LazyList(generator); | |
} | |
dropWhile(fn) { | |
const generator = dropWhile(fn)(this.#asGenerator()); | |
return new LazyList(generator); | |
} | |
map(fn) { | |
const generator = map(fn)(this.#asGenerator()); | |
return new LazyList(generator); | |
} | |
filter(fn) { | |
const generator = filter(fn)(this.#asGenerator()); | |
return new LazyList(generator); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment