source: Dev/trunk/src/client/dojox/lang/functional/linrec.js @ 529

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

Added Dojo 1.9.3 release.

File size: 4.3 KB
Line 
1dojo.provide("dojox.lang.functional.linrec");
2
3dojo.require("dojox.lang.functional.lambda");
4dojo.require("dojox.lang.functional.util");
5
6// This module provides recursion combinators:
7//      - a linear 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,
20                _x ="_x", _r_y_a = ["_r", "_y.a"];
21
22        df.linrec = function(
23                                        /*Function|String|Array*/ cond,
24                                        /*Function|String|Array*/ then,
25                                        /*Function|String|Array*/ before,
26                                        /*Function|String|Array*/ after){
27                // summary:
28                //              Generates a function for the linear recursion pattern.
29                //              All parameter functions are called 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                //              The returned value should be an array, which is used to call
43                //              the generated function recursively.
44                // above:
45                //              The lambda expression, which is called after the recursive step.
46                //              It accepts two parameters: the returned value from the recursive step, and
47                //              the original array of parameters used with all other functions.
48                //              The returned value will be returned as the value of the generated function.
49
50                var c, t, b, a, cs, ts, bs, as, dict1 = {}, dict2 = {},
51                        add2dict = function(x){ dict1[x] = 1; };
52                if(typeof cond == "string"){
53                        cs = inline(cond, _x, add2dict);
54                }else{
55                        c = df.lambda(cond);
56                        cs = "_c.apply(this, _x)";
57                        dict2["_c=_t.c"] = 1;
58                }
59                if(typeof then == "string"){
60                        ts = inline(then, _x, add2dict);
61                }else{
62                        t = df.lambda(then);
63                        ts = "_t.t.apply(this, _x)";
64                }
65                if(typeof before == "string"){
66                        bs = inline(before, _x, add2dict);
67                }else{
68                        b = df.lambda(before);
69                        bs = "_b.apply(this, _x)";
70                        dict2["_b=_t.b"] = 1;
71                }
72                if(typeof after == "string"){
73                        as = inline(after, _r_y_a, add2dict);
74                }else{
75                        a = df.lambda(after);
76                        as = "_a.call(this, _r, _y.a)";
77                        dict2["_a=_t.a"] = 1;
78                }
79                var locals1 = df.keys(dict1), locals2 = df.keys(dict2),
80                        f = new Function([], "var _x=arguments,_y,_r".concat(   // Function
81                                locals1.length ? "," + locals1.join(",") : "",
82                                locals2.length ? ",_t=_x.callee," + locals2.join(",") : t ? ",_t=_x.callee" : "",
83                                ";for(;!",
84                                cs,
85                                ";_x=",
86                                bs,
87                                "){_y={p:_y,a:_x}}_r=",
88                                ts,
89                                ";for(;_y;_y=_y.p){_r=",
90                                as,
91                                "}return _r"
92                        ));
93                if(c){ f.c = c; }
94                if(t){ f.t = t; }
95                if(b){ f.b = b; }
96                if(a){ f.a = a; }
97                return f;
98        };
99})();
100
101/*
102For documentation only:
103
1041) The original recursive version:
105
106var linrec1 = function(cond, then, before, after){
107        var cond   = df.lambda(cond),
108                then   = df.lambda(then),
109                before = df.lambda(before),
110                after  = df.lambda(after);
111        return function(){
112                if(cond.apply(this, arguments)){
113                        return then.apply(this, arguments);
114                }
115                var args = before.apply(this, arguments);
116                var ret  = arguments.callee.apply(this, args);
117                return after.call(this, ret, arguments);
118        };
119};
120
1212) The original iterative version (before minification and inlining):
122
123var linrec2 = function(cond, then, before, after){
124        var cond   = df.lambda(cond),
125                then   = df.lambda(then),
126                before = df.lambda(before),
127                after  = df.lambda(after);
128        return function(){
129                var args = arguments, top, ret;
130                // 1st part
131                for(; !cond.apply(this, args); args = before.apply(this, args)){
132                        top = {prev: top, args: args};
133                }
134                ret = then.apply(this, args);
135                //2nd part
136                for(; top; top = top.prev){
137                        ret = after.call(this, ret, top.args);
138                }
139                return ret;
140        };
141};
142
143*/
Note: See TracBrowser for help on using the repository browser.