/
core.js
52 lines (44 loc) · 1.82 KB
/
core.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
/* vim:set ts=2 sw=2 sts=2 expandtab */
/*jshint asi: true undef: true es5: true node: true devel: true
forin: true latedef: false supernew: true */
/*global define: true */
!(typeof(define) !== "function" ? function($) { $(typeof(require) !== 'function' ? (function() { throw Error('require unsupported'); }) : require, typeof(exports) === 'undefined' ? this : exports, typeof(module) === 'undefined' ? {} : module); } : define)(function(require, exports, module) {
"use strict";
exports.recur = recur
function recur(f) {
/**
Takes `f` function and returns wrapper in return, that may be
used for tail recursive algorithms. Note that returned funciton
is not side effect free and should not be called from anywhere
else during tail recursion. In other words if
`var f = recur(function foo() { ... bar() ... })`, then `bar`
should never call `f`. It is ok though for `bar` to call `recur(foo)`
instead.
## Examples
var sum = recur(function(x, y) {
return y > 0 ? sum(x + 1, y - 1) :
y < 0 ? sum(x - 1, y + 1) :
x
})
sum(20, 100000) // => 100020
**/
var result, active = false, accumulated = []
return function accumulator() {
// Every time accumulator is called, given set of parameters
// are accumulated.
accumulated.push(arguments)
// If accumulator is inactive (is not in the process of
// tail recursion) activate and start accumulating parameters.
if (!active) {
active = true
// If wrapped `f` performs tail call, then new set of parameters will
// be accumulated causing new iteration in the loop. If `f` does not
// performs tail call then accumulation is finished and `result` is
// returned.
while (accumulated.length) result = f.apply(this, accumulated.shift())
active = false
return result
}
}
}
});