source: Dev/branches/rest-dojo-ui/client/dojox/lang/functional/linrec.js @ 256

Last change on this file since 256 was 256, checked in by hendrikvanantwerpen, 13 years ago

Reworked project structure based on REST interaction and Dojo library. As
soon as this is stable, the old jQueryUI branch can be removed (it's
kept for reference).

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// Acknoledgements:
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.