on fb21e21 help sign in
elk/core-js/runtime/Signal.js
284 lines 8.8 kB history raw
2Elm.Signal = function() {
3 var send = function(node, timestep, changed) {
4 var kids = node.kids;
5 for (var i = kids.length; i--; ) {
6 kids[i].recv(timestep, changed, node.id);
7 }
8 };
9 /**
10 * @constructor
11 */
12 function input(base) {
13 this.id = Guid.guid();
14 this.value = base;
15 this.kids = [];
16 this.defaultNumberOfKids = 0;
17 this.recv = function(timestep, eid, v) {
18 var changed = eid === this.id;
19 if (changed) { this.value = v; }
20 send(this, timestep, changed);
21 return changed;
22 };
23 Dispatcher.inputs.push(this);
24 };
25 /**
26 * @constructor
27 */
28 function lift(func,args) {
29 this.id = Guid.guid();
30 this.value = null;
31 this.kids = [];
32 this.count = 0;
33 this.changed = false;
35 args.reverse();
36 this.recalc = function() {
37 var f = func;
38 for (var i = args.length; i--; ) {
39 f = f(args[i].value);
40 }
41 this.value = f;
42 };
43 this.recalc();
45 this.recv = function(timestep, changed, parentID) {
46 this.count += 1;
47 if (changed) { this.changed = true; }
48 if (this.count == args.length) {
49 if (this.changed) { this.recalc() }
50 send(this, timestep, this.changed);
51 this.changed = false;
52 this.count = 0;
53 }
54 };
55 for (var i = args.length; i--; ) {
56 args[i].kids.push(this);
57 }
58 };
59 /**
60 * @constructor
61 */
62 function fold(func,base,baseIsFunc,input) {
63 this.id = Guid.guid();
64 this.value = baseIsFunc ? base(input.value) : base;
65 this.kids = [];
66 this.recv = function(timestep, changed, parentID) {
67 if (changed) { this.value = func(input.value)(this.value); }
68 send(this, timestep, changed);
69 };
70 input.kids.push(this);
71 };
73 /**
74 * @constructor
75 */
76 function dropIf(pred,base,input) {
77 this.id = Guid.guid();
78 this.value = pred(input.value) ? base : input.value;
79 this.kids = [];
80 this.recv = function(timestep, changed, parentID) {
81 var chng = changed && !pred(input.value);
82 if (chng) { this.value = input.value; }
83 send(this, timestep, chng);
84 };
85 input.kids.push(this);
86 };
88 /**
89 * @constructor
90 */
91 function dropRepeats(input) {
92 this.id = Guid.guid();
93 this.value = input.value;
94 this.kids = [];
95 this.recv = function(timestep, changed, parentID) {
96 var chng = changed && !Value.eq(this.value,input.value);
97 if (chng) { this.value = input.value; }
98 send(this, timestep, chng);
99 };
100 input.kids.push(this);
101 };
103 var dropWhen = function(s1) { return function(b) { return function(s2) {
104 var pairs = new lift(function(x){return function(y){return [x,y];};},[s1,s2]);
105 var dropped = new dropIf(function(p){return p[0];},[true,b],pairs);
106 return new lift(function(p){return p[1];},[dropped]); }; };
107 };
109 /**
110 * @constructor
111 */
112 function timeIndex(pair,s) {
113 this.id = Guid.guid();
114 var t = (new window.Date).getTime();
115 this.value = pair ? Value.Tuple(t,s.value) : t;
116 this.kids = [];
117 this.recv = function(timestep, changed, parentID) {
118 if (changed) this.value = pair ? Value.Tuple(timestep, s.value) : timestep;
119 send(this, timestep, changed);
120 };
121 s.kids.push(this);
122 }
124 /**
125 * @constructor
126 */
127 function sampleOn(s1,s2) {
128 this.id = Guid.guid();
129 this.value = s2.value;
130 this.kids = [];
131 this.count = 0;
132 this.changed = false;
134 this.recv = function(timestep, changed, parentID) {
135 if (parentID === s1.id) this.changed = changed;
136 this.count += 1;
137 if (this.count == 2) {
138 if (this.changed) { this.value = s2.value; }
139 send(this, timestep, this.changed);
140 this.count = 0;
141 this.changed = false;
142 }
143 };
144 s1.kids.push(this);
145 s2.kids.push(this);
146 };
148 function delay(t) { return function(s) {
149 var delayed = new input(s.value);
150 var firstEvent = true;
151 function update(v) {
152 if (firstEvent) return;
153 setTimeout(function() { Dispatcher.notify(delayed.id,v); },t);
154 }
155 function first(a) { return function(b) { return a; }; }
156 var out = new sampleOn(delayed,new lift(first, [delayed, new lift(update,[s])]));
157 firstEvent = false;
158 return out;
159 };
160 }
162 /**
163 * @constructor
164 */
165 function merge(s1,s2) {
166 this.id = Guid.guid();
167 this.value = s1.value;
168 this.kids = [];
169 this.next = null;
170 this.count = 0;
171 this.changed = false;
173 this.recv = function(timestep, changed, parentID) {
174 this.count += 1;
175 if (changed) {
176 this.changed = true;
177 if (parentID == s2.id && this.next === null) { this.next = s2.value; }
178 if (parentID == s1.id) { this.next = s1.value; }
179 }
181 if (this.count == 2) {
182 if (this.changed) {
183 this.value = this.next;
184 this.next = null;
185 }
186 send(this, timestep, this.changed);
187 this.changed = false;
188 this.count = 0;
189 }
190 };
191 s1.kids.push(this);
192 s2.kids.push(this);
193 };
195 function merges(ss) {
196 function mrg(x) { return function(y) { return new merge(x,y); }; }
197 return Elm.List.foldl1(mrg)(ss);
198 }
200 function mergeEither(s1) { return function(s2) {
201 function f(s) { return function(x) { return [s,x]; }; }
202 return new merge(new lift(f,[s1]), new lift(f,[s2]));
203 };
204 }
206 function average(sampleSize) { return function(s) {
207 var sample = new Array(sampleSize);
208 var i = sampleSize;
209 while (i--) sample[i] = 0;
210 i = 0;
211 var full = false;
212 var total = 0;
213 function f(n) {
214 total += n - sample[i];
215 sample[i] = n;
216 var avg = total / Math.max(1, full ? sampleSize : i);
217 if (++i == sampleSize) { full = true; i = 0; }
218 return avg;
219 }
220 return new lift(f, [s]);
221 };
222 }
224 return {
225 constant : function(v) { return new input(v); },
226 lift : function(f){return function(e){return new lift(f,[e]);};},
227 lift2 : function(f) {
228 return function(e1) { return function(e2) {
229 return new lift(f, [e1,e2]); };};},
230 lift3 : function(f) {
231 return function(e1) { return function(e2) {
232 return function(e3){return new lift(f,[e1,e2,e3]);};};};},
233 lift4 : function(f) {
234 return function(e1) { return function(e2) {
235 return function(e3) { return function(e4) {
236 return new lift(f, [e1,e2,e3,e4]);};};};};},
237 lift5 : function(f) {
238 return function(e1) { return function(e2) {
239 return function(e3) { return function(e4) {
240 return function(e5) {
241 return new lift(f, [e1,e2,e3,e4,e5]);};};};};};},
242 lift6 : function(f) { return function(e1) { return function(e2) {
243 return function(e3) { return function(e4) {
244 return function(e5) { return function(e6) {
245 return new lift(f, [e1,e2,e3,e4,e5,e6]); };};};};};};},
246 lift7 : function(f) { return function(e1) { return function(e2) {
247 return function(e3) { return function(e4) {
248 return function(e5) { return function(e6) {
249 return function(e7) {
250 return new lift(f, [e1,e2,e3,e4,e5,e6,e7]);};};};};};};};},
251 lift8 : function(f) { return function(e1) { return function(e2) {
252 return function(e3) { return function(e4) {
253 return function(e5) { return function(e6) {
254 return function(e7) { return function(e8) {
255 return new lift(f, [e1,e2,e3,e4,e5,e6,e7,e8]);};};};};};};};};},
256 foldp : function(f) { return function(b) { return function(e) {
257 return new fold(f,b,false,e); }; }; },
258 foldp$ : function(f) { return function(b) { return function(e) {
259 return new fold(f,b,true,e); }; }; },
260 foldp1 : function(f) { return function(e) {
261 return new fold(f,function(x){return x;},true,e); }; },
262 delay : delay,
263 merge : function(s1) { return function(s2) { return new merge(s1,s2)}; },
264 merges : merges,
265 mergeEither : mergeEither,
266 average : average,
267 count : function(sig) {
268 var incr = function(_){return function(c){return c+1;};};
269 return new fold(incr,0,false,sig) },
270 countIf : function(pred) { return function(sig) {
271 var incr = function(x){return function(c){return pred(x) ? c+1 : c;};};
272 return new fold(incr,0,false,sig) }; },
273 keepIf : function(pred) { return function(base) { return function(sig) {
274 return new dropIf(function(x) { return !pred(x)},base,sig); }; }; },
275 dropIf : function(pred) { return function(base) { return function(sig) {
276 return new dropIf(pred,base,sig); }; }; },
277 keepWhen : function(s) { return dropWhen(new lift(function(b){return !b;},[s])); },
278 dropWhen : dropWhen,
279 dropRepeats : function(s) { return new dropRepeats(s);},
280 sampleOn : function(s1){return function(s2){return new sampleOn(s1,s2);};},
281 timestamp : function(s) { return new timeIndex(true, s); },
282 timeOf : function(s) { return new timeIndex(false, s); }
283 };
284}();