Skip to content

Instantly share code, notes, and snippets.

@odf
Last active November 20, 2019 09:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save odf/fe014d74ff1ce373e7a88f6e46f0af8a to your computer and use it in GitHub Desktop.
Save odf/fe014d74ff1ce373e7a88f6e46f0af8a to your computer and use it in GitHub Desktop.
Flattening an infinite list of infinite lists in JavaScript via Cantor diagonalisation
class Seq {
toArray() {
const a = [];
for (const x of this)
a.push(x);
return a;
}
toString() {
return this.toArray().join(' -> ');
}
map(fn) {
return this.isNil ? nil :
cons(fn(this.first()), () => this.rest().map(fn));
}
take(n) {
if (this.isNil || n <= 0)
return nil;
else
return cons(this.first(), () => this.rest().take(n - 1));
}
split(fill=null) {
if (this.isNil)
return [this, fill];
else
return [this.first(), this.rest()];
}
};
Seq.prototype[Symbol.iterator] = function*() {
let s = this;
while (!s.isNil) {
yield s.first();
s = s.rest();
}
};
export const nil = new Seq();
nil.isNil = true;
nil.first = () => { throw new Error('empty sequence has no first element'); };
nil.rest = () => nil;
class Cons extends Seq {
constructor(firstVal, restFn) {
super();
this.isNil = false;
this.first = () => firstVal;
this.rest = () => {
const val = restFn && restFn();
this.rest = () => val;
return val;
}
}
}
export const cons = (firstVal, restFn) => new Cons(firstVal, restFn);
export const upFrom = start => cons(start, () => upFrom(start + 1));
export function cantor(lists) {
let unused = lists;
let active = [];
let next = 0;
function _cantor() {
if (next >= active.length) {
const [xs, rest] = unused.split(nil);
active.push(xs);
unused = rest;
next = 0;
}
const [x, rest] = active[next].split();
active[next] = rest;
next += 1;
return cons(x, () => _cantor());
}
return _cantor();
}
if (require.main == module) {
const test = t => {
const s = eval(t);
console.log(`${t}:\n ${s}`);
console.log();
};
test('nil');
test('upFrom(10).take(5)');
test('cantor(upFrom(1).map(x => upFrom(1).map(y => [x, y]))).take(25)');
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment