source: Dev/trunk/src/client/dojox/lang/functional/tailrec.js @ 532

Last change on this file since 532 was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

File size: 3.6 KB
Line 
1dojo.provide("dojox.lang.functional.tailrec");
2
3dojo.require("dojox.lang.functional.lambda");
4dojo.require("dojox.lang.functional.util");
5
6// This module provides recursion combinators:
7//      - a tail recursion combinator.
8
9// Acknowledgements:
10//      - recursion combinators are inspired by Manfred von Thun's article
11//              "Recursion Theory and Joy"
12//              (http://www.latrobe.edu.au/philosophy/phimvt/joy/j05cmp.html)
13
14// Notes:
15//      - recursion combinators produce a function, which implements
16//      their respective recusion patterns. String lambdas are inlined, if possible.
17
18(function(){
19        var df = dojox.lang.functional, inline = df.inlineLambda, _x ="_x";
20
21        df.tailrec = function(
22                                        /*Function|String|Array*/ cond,
23                                        /*Function|String|Array*/ then,
24                                        /*Function|String|Array*/ before){
25                // summary:
26                //              Generates a function for the tail recursion pattern. This is the simplified
27                //              version of the linear recursive combinator without the "after" function,
28                //              and with the modified "before" function. All parameter functions are called
29                //              in the context of "this" object.
30                // cond:
31                //              The lambda expression, which is used to detect the termination of recursion.
32                //              It accepts the same parameter as the generated recursive function itself.
33                //              This function should return "true", if the recursion should be stopped,
34                //              and the "then" part should be executed. Otherwise the recursion will proceed.
35                // then:
36                //              The lambda expression, which is called upon termination of the recursion.
37                //              It accepts the same parameters as the generated recursive function itself.
38                //              The returned value will be returned as the value of the generated function.
39                // before:
40                //              The lambda expression, which is called before the recursive step.
41                //              It accepts the same parameter as the generated recursive function itself,
42                //              and returns an array of arguments for the next recursive call of
43                //              the generated function.
44
45                var c, t, b, cs, ts, bs, dict1 = {}, dict2 = {},
46                        add2dict = function(x){ dict1[x] = 1; };
47                if(typeof cond == "string"){
48                        cs = inline(cond, _x, add2dict);
49                }else{
50                        c = df.lambda(cond);
51                        cs = "_c.apply(this, _x)";
52                        dict2["_c=_t.c"] = 1;
53                }
54                if(typeof then == "string"){
55                        ts = inline(then, _x, add2dict);
56                }else{
57                        t = df.lambda(then);
58                        ts = "_t.t.apply(this, _x)";
59                }
60                if(typeof before == "string"){
61                        bs = inline(before, _x, add2dict);
62                }else{
63                        b = df.lambda(before);
64                        bs = "_b.apply(this, _x)";
65                        dict2["_b=_t.b"] = 1;
66                }
67                var locals1 = df.keys(dict1), locals2 = df.keys(dict2),
68                        f = new Function([], "var _x=arguments,_t=_x.callee,_c=_t.c,_b=_t.b".concat(    // Function
69                                locals1.length ? "," + locals1.join(",") : "",
70                                locals2.length ? ",_t=_x.callee," + locals2.join(",") : t ? ",_t=_x.callee" : "",
71                                ";for(;!",
72                                cs,
73                                ";_x=",
74                                bs,
75                                ");return ",
76                                ts
77                        ));
78                if(c){ f.c = c; }
79                if(t){ f.t = t; }
80                if(b){ f.b = b; }
81                return f;
82        };
83})();
84
85/*
86For documentation only:
87
881) The original recursive version:
89
90var tailrec1 = function(cond, then, before){
91        var cond   = df.lambda(cond),
92                then   = df.lambda(then),
93                before = df.lambda(before);
94        return function(){
95                if(cond.apply(this, arguments)){
96                        return then.apply(this, arguments);
97                }
98                var args = before.apply(this, arguments);
99                return arguments.callee.apply(this, args);
100        };
101};
102
1032) The original iterative version (before minification and inlining):
104
105var tailrec2 = function(cond, then, before){
106        var cond   = df.lambda(cond),
107                then   = df.lambda(then),
108                before = df.lambda(before);
109        return function(){
110                var args = arguments;
111                for(; !cond.apply(this, args); args = before.apply(this, args));
112                return then.apply(this, args);
113        };
114};
115
116*/
Note: See TracBrowser for help on using the repository browser.