on 577fc17 help sign in
395 lines 10 kB history raw
1Elm.Native.List = {};
2Elm.Native.List.make = function(elm) {
3 elm.Native = elm.Native || {};
4 elm.Native.List = elm.Native.List || {};
5 if (elm.Native.List.values) return elm.Native.List.values;
6 if ('values' in Elm.Native.List)
7 return elm.Native.List.values = Elm.Native.List.values;
9 var Utils = Elm.Native.Utils.make(elm);
11 // TODO: Improve Nil handling
12 // We can change places like: if (xs.ctor === '[]') ... to if (xs === Nil) ...
13 // but only if we're confident Nil can only be defined once.
14 // Currently (27Mar2013) each module can have different instantiations, so multiple Nil objects can exist
15 // (and if they're used interchangeably then direct object comparison fails where ctor doesn't).
16 // So, this can only be fixed when modules initialisation is also fixed.
17 // The performance overhead of the .ctor calls is 5-10% according to jsperf (depending on fn + list size)
18 // (on firefox 19)
20 var Nil = { ctor:'[]' };
22 // using freeze for every cons would be nice but is a huge (9x on firefox 19)
23 // performance penalty
24 function Cons(hd,tl) { return { ctor:"::", _0:hd, _1:tl }; }
26 function throwError(f) {
27 throw new Error("Function '" + f + "' expects a non-empty list!");
28 }
30 function toArray(xs) {
31 var out = [];
32 while (xs.ctor !== '[]') {
33 out.push(xs._0);
34 xs = xs._1;
35 }
36 return out;
37 }
39 function fromArray(arr) {
40 var out = Nil;
41 for (var i = arr.length; i--; ) {
42 out = Cons(arr[i], out);
43 }
44 return out;
45 }
47 function range(lo,hi) {
48 var lst = Nil;
49 if (lo <= hi) {
50 do { lst = Cons(hi,lst) } while (hi-->lo);
51 }
52 return lst
53 }
55 function append(xs,ys) {
56 // append Text
57 if (xs.text || ys.text) {
58 return Utils.txt(Utils.makeText(xs) + Utils.makeText(ys));
59 }
61 // append Strings
62 if (typeof xs === "string") return xs + ys;
64 // append Lists
65 if (xs.ctor === '[]') { return ys; }
66 var root = Cons(xs._0, Nil);
67 var curr = root;
68 xs = xs._1;
69 while (xs.ctor !== '[]') {
70 curr._1 = Cons(xs._0, Nil);
71 xs = xs._1;
72 curr = curr._1;
73 }
74 curr._1 = ys;
75 return root;
76 }
78 function head(v) { return v.ctor === '[]' ? throwError('head') : v._0; }
79 function tail(v) { return v.ctor === '[]' ? throwError('tail') : v._1; }
81 function last(xs) {
82 if (xs.ctor === '[]') { throwError('last'); }
83 var out = xs._0;
84 while (xs.ctor !== '[]') {
85 out = xs._0;
86 xs = xs._1;
87 }
88 return out;
89 }
91 function map(f, xs) {
92 var arr = [];
93 while (xs.ctor !== '[]') {
94 arr.push(f(xs._0));
95 xs = xs._1;
96 }
97 return fromArray(arr);
98 }
100 // f defined similarly for both foldl and foldr (NB: different from Haskell)
101 // ie, foldl : (a -> b -> b) -> b -> [a] -> b
102 function foldl(f, b, xs) {
103 var acc = b;
104 while (xs.ctor !== '[]') {
105 acc = A2(f, xs._0, acc);
106 xs = xs._1;
107 }
108 return acc;
109 }
111 function foldr(f, b, xs) {
112 var arr = toArray(xs);
113 var acc = b;
114 for (var i = arr.length; i--; ) {
115 acc = A2(f, arr[i], acc);
116 }
117 return acc;
118 }
120 function foldl1(f, xs) {
121 return xs.ctor === '[]' ? throwError('foldl1') : foldl(f, xs._0, xs._1);
122 }
124 function foldr1(f, xs) {
125 if (xs.ctor === '[]') { throwError('foldr1'); }
126 var arr = toArray(xs);
127 var acc = arr.pop();
128 for (var i = arr.length; i--; ) {
129 acc = A2(f, arr[i], acc);
130 }
131 return acc;
132 }
134 function scanl(f, b, xs) {
135 var arr = toArray(xs);
136 arr.unshift(b);
137 var len = arr.length;
138 for (var i = 1; i < len; ++i) {
139 arr[i] = A2(f, arr[i], arr[i-1]);
140 }
141 return fromArray(arr);
142 }
144 function scanl1(f, xs) {
145 return xs.ctor === '[]' ? throwError('scanl1') : scanl(f, xs._0, xs._1);
146 }
148 function filter(pred, xs) {
149 var arr = [];
150 while (xs.ctor !== '[]') {
151 if (pred(xs._0)) { arr.push(xs._0); }
152 xs = xs._1;
153 }
154 return fromArray(arr);
155 }
157 function length(xs) {
158 var out = 0;
159 while (xs.ctor !== '[]') {
160 out += 1;
161 xs = xs._1;
162 }
163 return out;
164 }
166 function member(x, xs) {
167 while (xs.ctor !== '[]') {
168 if (Utils.eq(x,xs._0)) return true;
169 xs = xs._1;
170 }
171 return false;
172 }
174 function reverse(xs) { return fromArray(toArray(xs).reverse()); }
176 function concat(xss) {
177 if (xss.ctor === '[]') return xss;
178 var arr = toArray(xss);
179 var xs = arr[arr.length-1];
180 for (var i = arr.length-1; i--; ) {
181 xs = append(arr[i], xs);
182 }
183 return xs;
184 }
186 function all(pred, xs) {
187 while (xs.ctor !== '[]') {
188 if (!pred(xs._0)) return false;
189 xs = xs._1;
190 }
191 return true;
192 }
194 function any(pred, xs) {
195 while (xs.ctor !== '[]') {
196 if (pred(xs._0)) return true;
197 xs = xs._1;
198 }
199 return false;
200 }
202 function zip(xs, ys) {
203 var arr = [];
204 while (xs.ctor !== '[]' && ys.ctor !== '[]') {
205 arr.push(Utils.Tuple2(xs._0, ys._0));
206 xs = xs._1;
207 ys = ys._1;
208 }
209 return fromArray(arr);
210 }
212 function zipWith(f, xs, ys) {
213 var arr = [];
214 while (xs.ctor !== '[]' && ys.ctor !== '[]') {
215 arr.push(A2(f, xs._0, ys._0));
216 xs = xs._1;
217 ys = ys._1;
218 }
219 return fromArray(arr);
220 }
222 function zipWith3(f, xs, ys, zs) {
223 var arr = [];
224 while (xs.ctor !== '[]' && ys.ctor !== '[]' && zs.ctor !== '[]') {
225 arr.push(A3(f, xs._0, ys._0, zs._0));
226 xs = xs._1;
227 ys = ys._1;
228 zs = zs._1;
229 }
230 return fromArray(arr);
231 }
233 function zipWith4(f, ws, xs, ys, zs) {
234 var arr = [];
235 while ( ws.ctor !== '[]'
236 && xs.ctor !== '[]'
237 && ys.ctor !== '[]'
238 && zs.ctor !== '[]')
239 {
240 arr.push(A4(f, ws._0, xs._0, ys._0, zs._0));
241 ws = ws._1;
242 xs = xs._1;
243 ys = ys._1;
244 zs = zs._1;
245 }
246 return fromArray(arr);
247 }
249 function zipWith5(f, vs, ws, xs, ys, zs) {
250 var arr = [];
251 while ( vs.ctor !== '[]'
252 && ws.ctor !== '[]'
253 && xs.ctor !== '[]'
254 && ys.ctor !== '[]'
255 && zs.ctor !== '[]')
256 {
257 arr.push(A5(f, vs._0, ws._0, xs._0, ys._0, zs._0));
258 vs = vs._1;
259 ws = ws._1;
260 xs = xs._1;
261 ys = ys._1;
262 zs = zs._1;
263 }
264 return fromArray(arr);
265 }
267 function sort(xs) {
268 return fromArray(toArray(xs).sort(Utils.cmp));
269 }
271 function sortBy(f, xs) {
272 return fromArray(toArray(xs).sort(function(a,b){
273 return Utils.cmp(f(a), f(b));
274 }));
275 }
277 function sortWith(f, xs) {
278 return fromArray(toArray(xs).sort(function(a,b){
279 var ord = f(a)(b).ctor;
280 return ord === 'EQ' ? 0 : ord === 'LT' ? -1 : 1;
281 }));
282 }
284 function nth(xs, n) {
285 return toArray(xs)[n];
286 }
288 function take(n, xs) {
289 var arr = [];
290 while (xs.ctor !== '[]' && n > 0) {
291 arr.push(xs._0);
292 xs = xs._1;
293 --n;
294 }
295 return fromArray(arr);
296 }
298 function drop(n, xs) {
299 while (xs.ctor !== '[]' && n > 0) {
300 xs = xs._1;
301 --n;
302 }
303 return xs;
304 }
306 function repeat(n, x) {
307 var arr = [];
308 var pattern = [x];
309 while (n > 0) {
310 if (n & 1) arr = arr.concat(pattern);
311 n >>= 1, pattern = pattern.concat(pattern);
312 }
313 return fromArray(arr);
314 }
316 function join(sep, xss) {
317 if (sep.text) {
318 sep = Utils.makeText(sep);
319 xss = toArray(xss);
320 for (var i = xss.length; i--; ) {
321 xss[i] = Utils.makeText(xss[i]);
322 }
323 return Utils.txt(xss.join(sep));
324 }
325 if (typeof sep === 'string') return toArray(xss).join(sep);
326 if (xss.ctor === '[]') return Nil;
327 var s = toArray(sep);
328 var out = toArray(xss._0);
329 xss = xss._1;
330 while (xss.ctor !== '[]') {
331 out = out.concat(s, toArray(xss._0));
332 xss = xss._1;
333 }
334 return fromArray(out);
335 }
337 /*
338 * Only to be used internally; do some side effects for each elem
339 */
340 function each(action, xs) {
341 while(xs.ctor !== '[]') {
342 action(xs._0);
343 xs = xs._1;
344 }
345 }
347 Elm.Native.List.values = {
348 Nil:Nil,
349 Cons:Cons,
350 cons:F2(Cons),
351 toArray:toArray,
352 fromArray:fromArray,
353 range:range,
354 append:append,
356 head:head,
357 tail:tail,
358 last:last,
360 map:F2(map),
361 foldl:F3(foldl),
362 foldr:F3(foldr),
364 foldl1:F2(foldl1),
365 foldr1:F2(foldr1),
366 scanl:F3(scanl),
367 scanl1:F2(scanl1),
368 filter:F2(filter),
369 length:length,
370 member:F2(member),
371 reverse:reverse,
372 concat:concat,
374 all:F2(all),
375 any:F2(any),
376 zipWith :F3(zipWith ),
377 zipWith3:F4(zipWith3),
378 zipWith4:F5(zipWith4),
379 zipWith5:F6(zipWith5),
380 zip:F2(zip),
381 sort:sort,
382 sortBy:F2(sortBy),
383 sortWith:F2(sortWith),
384 nth:F2(nth),
385 take:F2(take),
386 drop:F2(drop),
387 repeat:F2(repeat),
389 join:F2(join),
391 each:each
392 };
393 return elm.Native.List.values = Elm.Native.List.values;
395};