-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathlazy.js
99 lines (90 loc) · 2.27 KB
/
lazy.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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
function Lazy(fn, args, context) {
if (!args)
return Lazy.fmap(fn);
if (!this.lazy)
this.lazy = true;
this.execute = function() {
for (var i=0, l=args.length; i<l; i++)
if (args[i] instanceof Lazy)
args[i] = args[i].execute();
if (context instanceof Lazy)
context = context.execute();
var result = fn.apply(context, args);
this.execute = Function.const(result);
return result;
};
}
Lazy.prototype.lazy = true;
Lazy.fmap = function fmap(fn) {
// lift :: (a -> b) -> ((Lazy a|a)... -> Lazy b)
return function() {
return new Lazy(fn, arguments, this);
};
};
/* https://github.com/fantasyland/fantasy-land */
// Functor
Lazy.prototype.map = function map(fn) {
return new Lazy(fn, [this], arguments[1]);
// return new Lazy(this.execute.map(fn), []);
};
// Applicative
Lazy.prototype.ap = function ap(g) {
return new Lazy(Function.prototype.call, [null, g], this);
// return new Lazy(function(fn, v) { fn(v); }, [this, g]);
};
// Applicative, Monad
Lazy.prototype.of = Lazy.of = function(v) {
var l = Object.create(Lazy.prototype);
l.execute = Function.const(v);
return l;
};
// Chain, Monad
Lazy.prototype.chain = function chain(fn) {
return new Lazy(function(self) {
return fn(self).execute();
}, [this]);
};
// ==============================
// functional, without instances:
function lazy(fn, args) {
if (!args)
return fmap(fn);
var result;
function execute() {
if (!args)
return result;
for (var i=0, l=args.length; i<l; i++) {
var a = args[i];
if (a && a.lazy && typeof a.execute == "function")
args[i] = a.execute();
}
result = fn.apply(null, args);
fn = args = null; // collect garbage
execute.execute = Function.const(result);
return result;
}
execute.execute = execute;
execute.lazy = true;
return execute;
}
function fmap(fn) {
// lift :: (a -> b) -> (()->a|a)... -> (()->b))
return function() {
if (this == null)
return lazy(fn, arguments);
Array.prototype.unshift.call(arguments, this);
return lazy(Function.prototype.call.bind(fn), arguments);
};
}
/* better garbage collection (of fn and args) with this pattern:
function lazy(fn, args, context) {
var result = null;
var todo = function() {
todo = false;
return result = fn.apply(context, args);
};
return function() {
return !todo ? result : todo();
};
}
*/