Skip to content

Commit f0b610f

Browse files
Merge pull request #103 from sanctuary-js/davidchambers/no-apply
remove uses of Function#apply to accommodate large arrays
2 parents 25d05a1 + 539d393 commit f0b610f

File tree

3 files changed

+39
-10
lines changed

3 files changed

+39
-10
lines changed

bench/old-vs-new.js

+12
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,16 @@ var Identity = require('../test/Identity');
1010
var shuffle = require('../test/shuffle');
1111

1212

13+
// chainRecArrayNumber :: (Number -> c, Number -> c, Number) -> Array c
14+
function chainRecArrayNumber(next, done, x) {
15+
return [done(x), (x <= 1 ? done : next)(x - 1)];
16+
}
17+
18+
// double :: a -> Array2 a a
19+
function double(x) {
20+
return [x, x];
21+
}
22+
1323
// inc :: Number -> Number
1424
function inc(x) {
1525
return x + 1;
@@ -29,8 +39,10 @@ var shuffledArray = (function() {
2939
var shuffledList = L.fromArray(shuffledArray);
3040

3141
module.exports = benchmark(oldZ, newZ, {leftHeader: 'old', rightHeader: 'new'}, prep({
42+
'functions.chainRec.Array': function(Z) { Z.chainRec(Array, chainRecArrayNumber, 100); },
3243
'functions.of.Array': function(Z) { Z.of(Array, 42); },
3344
'functions.of.Identity': function(Z) { Z.of(Identity, 42); },
45+
'methods.chain.Array': function(Z) { Z.chain(double, shuffledArray); },
3446
'methods.equals.Identity': function(Z) { Z.equals(Identity(0), Identity(0)); },
3547
'methods.equals.Object': function(Z) { Z.equals({x: 0, y: 0}, {y: 0, x: 0}); },
3648
'methods.map.Array': function(Z) { Z.map(inc, [1, 2, 3]); },

index.js

+24-10
Original file line numberDiff line numberDiff line change
@@ -747,17 +747,27 @@
747747

748748
// Array$chainRec :: ((a -> c, b -> c, a) -> Array c, a) -> Array b
749749
function Array$chainRec(f, x) {
750-
var $todo = [x];
751-
var $done = [];
752-
while ($todo.length > 0) {
753-
var xs = f(iterationNext, iterationDone, $todo.shift());
754-
var $more = [];
755-
for (var idx = 0; idx < xs.length; idx += 1) {
756-
(xs[idx].done ? $done : $more).push(xs[idx].value);
750+
var result = [];
751+
var nil = {};
752+
var todo = {head: x, tail: nil};
753+
while (todo !== nil) {
754+
var more = nil;
755+
var steps = f(iterationNext, iterationDone, todo.head);
756+
for (var idx = 0; idx < steps.length; idx += 1) {
757+
var step = steps[idx];
758+
if (step.done) {
759+
result.push(step.value);
760+
} else {
761+
more = {head: step.value, tail: more};
762+
}
763+
}
764+
todo = todo.tail;
765+
while (more !== nil) {
766+
todo = {head: more.head, tail: todo};
767+
more = more.tail;
757768
}
758-
Array.prototype.unshift.apply($todo, $more);
759769
}
760-
return $done;
770+
return result;
761771
}
762772

763773
// Array$zero :: () -> Array a
@@ -825,7 +835,11 @@
825835
// Array$prototype$chain :: Array a ~> (a -> Array b) -> Array b
826836
function Array$prototype$chain(f) {
827837
var result = [];
828-
this.forEach(function(x) { Array.prototype.push.apply(result, f(x)); });
838+
for (var idx = 0; idx < this.length; idx += 1) {
839+
for (var idx2 = 0, xs = f(this[idx]); idx2 < xs.length; idx2 += 1) {
840+
result.push(xs[idx2]);
841+
}
842+
}
829843
return result;
830844
}
831845

test/index.js

+3
Original file line numberDiff line numberDiff line change
@@ -1177,6 +1177,7 @@ test('chain', function() {
11771177
eq(Z.chain(repeat, abs)(-3), [-3, -3, -3]);
11781178
eq(Z.chain(identInc, Identity(42)), Identity(43));
11791179
eq(Z.chain(identity, Identity(Identity(0))), Identity(0));
1180+
eq(Z.chain(identity, [new Array(1e6).join('x').split('')]).length, 999999);
11801181
});
11811182

11821183
test('join', function() {
@@ -1217,6 +1218,8 @@ test('chainRec', function() {
12171218
}
12181219

12191220
eq(Z.chainRec(Function, stepper, 0)({step: 2, inc: 100}), 30100);
1221+
1222+
eq(Z.chainRec(Array, function(next, done, n) { return n === 0 ? [done(0)] : Z.map(next, repeat(n)(0)); }, 1e6).length, 1e6);
12201223
});
12211224

12221225
test('alt', function() {

0 commit comments

Comments
 (0)