Skip to content

Instantly share code, notes, and snippets.

@buzzdecafe
Last active December 19, 2015 12:18
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 buzzdecafe/5953596 to your computer and use it in GitHub Desktop.
Save buzzdecafe/5953596 to your computer and use it in GitHub Desktop.
generators again. tweaking scott's generators for ramda (cf. https://github.com/CrossEye/ramda/blob/master/examples/generators.js)
// require("ramda");
var gens = (function() {
var trampoline = function(fn) {
var result = fn.apply(this, tail(arguments));
while (typeof result == "function") {
result = result();
}
return result;
};
var cadr = function(list) {
return list[1];
};
var generator = function(seed, current, step) {
return [
current(seed),
function() {
return generator(step(seed), current, step);
}
];
};
var genTake = function(n, gen) {
var take = function(ctr, g, ret) {
return (ctr == 0) ? ret : take(ctr - 1, cadr(g)(), append(head(g), ret))
};
return trampoline(take, n, gen, []);
};
var genSkip = function(n, gen) {
return (n <= 0) ? gen : genSkip(n - 1, cadr(gen)());
};
var genMap = function(fn, gen) {
return [
fn(head(gen)),
function() {
return genMap(fn, cadr(gen)());
}
];
};
var genFilter = function(fn, gen) {
var head = head(gen);
while (!fn(head)) {
gen = tail(gen);
head = head(gen);
}
return [
head,
function() {
return genFilter(fn, cadr(gen)());
}
];
};
return {
generator: generator,
take: genTake,
skip: genSkip,
map: genMap,
filter: genFilter
};
}());
ramda.installTo(this);
var identity = function(x) {return x;};
var square = function(n) {return n * n;};
var even = function(n) {return !(n % 2);};
var ints = gens.generator(0, identity, function(n) {return n + 1;});
console.log(gens.take(10, ints));
console.log(gens.take(5, gens.skip(10, ints)));
var fibonacci = gens.generator(
[0, 1],
function(pair) {return pair[0];},
function(pair) {return [pair[1], pair[0] + pair[1]];}
);
console.log(gens.take(20, fibonacci));
console.log(gens.take(10, gens.map(square, ints)));
console.log(gens.take(5, gens.filter(even, fibonacci)));
// ramda simple iterative slice
var slice = function(args, from, to) {
var i, arr = [];
from = from || 0;
to = to || args.length;
for (i = from; i < to; i++) {
arr[arr.length] = args[i];
}
return arr;
};
// option #1: type-check. eeewwwwww.
var slice = function(args, from, to) {
var i, arr = [];
from = from || 0;
to = to || args.length;
for (i = from; i < to; i++) {
arr[arr.length] = args[i];
}
return arr.length === 1 && isGenerator(arr[0]) ? arr[0]() : arr;
};
// so what would isGenerator look like?
var isGenerator = function(fn) {
// stick a property on the generator function?
return fn.isGeneratorFn === true;
// use a constructed object?
};
// option #2: use a generator object instead of a list, and rewrite tail instead
var tail = R.tail = function(arr) {
arr = arr || EMPTY;
if (arr instanceof Generator) {
return arr[1]();
}
return (arr.length > 1) ? slice(arr, 1) : EMPTY;
};
// or maybe the generator object has its own tail method, we can call that instead
var tail = R.tail = function(arr) {
arr = arr || EMPTY;
if (typeof arr.tail === "function") {
return arr.tail();
}
return (arr.length > 1) ? slice(arr, 1) : EMPTY;
};
// option #3: Generator has the following structure:
// { "0": z, tail: someFn, length: Infinity }
var tail = R.tail = function(arr) {
arr = arr || EMPTY;
if (arr.length === Infinity) {
return arr.tail();
}
return (arr.length > 1) ? slice(arr, 1) : EMPTY;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment