@@ -7,7 +7,11 @@ Elm.Native.List = function(elm) {
8 var Utils = Elm.Native.Utils(elm);
8 var Utils = Elm.Native.Utils(elm);
10+ // freeze is universally supported and as a singleton introduces little performance penalty
11+ // for a small amount of object safety
10− var Nil = { ctor:'Nil' };
12+ var Nil = Object.freeze({ ctor:'Nil' });
14+ // using freeze for every cons would be nice but is a huge (9x on firefox 19) performance penalty
11 function Cons(hd,tl) { return { ctor:"Cons", _0:hd, _1:tl }; }
15 function Cons(hd,tl) { return { ctor:"Cons", _0:hd, _1:tl }; }
13 function throwError(f) {
17 function throwError(f) {
@@ -16,13 +20,13 @@ Elm.Native.List = function(elm) {
17 function toArray(xs) {
21 function toArray(xs) {
18 var out = [];
22 var out = [];
19− while (xs.ctor === "Cons") {
23+ while (xs !== Nil) {
20 out.push(xs._0);
24 out.push(xs._0);
21 xs = xs._1;
25 xs = xs._1;
23 return out;
27 return out;
26 function fromArray(arr) {
30 function fromArray(arr) {
27 var out = Nil;
31 var out = Nil;
28 for (var i = arr.length; i--; ) {
32 for (var i = arr.length; i--; ) {
@@ -41,11 +45,11 @@ Elm.Native.List = function(elm) {
42 function append(xs,ys) {
46 function append(xs,ys) {
43 if (typeof xs === "string") { return xs.concat(ys); }
47 if (typeof xs === "string") { return xs.concat(ys); }
44− if (xs.ctor === "Nil") { return ys; }
48+ if (xs === Nil) { return ys; }
45 var root = Cons(xs._0. Nil);
49 var root = Cons(xs._0. Nil);
46 var curr = root;
50 var curr = root;
47 xs = xs._1;
51 xs = xs._1;
48− while (xs.ctor==="Cons") {
52+ while (xs !== Nil) {
49 curr._1 = Cons(xs._0. Nil);
53 curr._1 = Cons(xs._0. Nil);
50 xs = xs._1;
54 xs = xs._1;
51 curr = curr._1;
55 curr = curr._1;
@@ -54,13 +58,13 @@ Elm.Native.List = function(elm) {
54 return root;
58 return root;
57− function head(v) { return v.ctor === "Nil" ? throwError('head') : v._0; }
61+ function head(v) { return v === Nil ? throwError('head') : v._0; }
58− function tail(v) { return v.ctor === "Nil" ? throwError('tail') : v._1; }
62+ function tail(v) { return v === Nil ? throwError('tail') : v._1; }
60 function last(xs) {
64 function last(xs) {
61− if (xs.ctor === "Nil") { throwError('last'); }
65+ if (xs === Nil) { throwError('last'); }
62 var out = xs._0;
66 var out = xs._0;
63− while (xs.ctor === "Cons") {
67+ while (xs !== Nil) {
64 out = xs._0;
68 out = xs._0;
65 xs = xs._1;
69 xs = xs._1;
@@ -69,17 +73,19 @@ Elm.Native.List = function(elm) {
70 function map(f, xs) {
74 function map(f, xs) {
71 var arr = [];
75 var arr = [];
72− while (xs.ctor === "Cons") {
76+ while (xs !== Nil) {
73 arr.push(f(xs._0));
77 arr.push(f(xs._0));
74 xs = xs._1;
78 xs = xs._1;
76 return fromArray(arr);
80 return fromArray(arr);
83+ // f defined similarly for both foldl and foldr (NB: different from Haskell)
84+ // ie, foldl :: (a -> b -> b) -> b -> [a] -> b
79 function foldl(f, b, xs) {
85 function foldl(f, b, xs) {
80 var acc = b;
86 var acc = b;
81− while (xs.ctor === "Cons") {
87+ while (xs !== Nil) {
82− acc = f(xs._0)(acc);
88+ acc = A2(f, xs._0, acc);
83 xs = xs._1;
89 xs = xs._1;
85 return acc;
91 return acc;
@@ -89,17 +95,17 @@ Elm.Native.List = function(elm) {
89 var arr = toArray(xs);
95 var arr = toArray(xs);
90 var acc = b;
96 var acc = b;
91 for (var i = arr.length; i--; ) {
97 for (var i = arr.length; i--; ) {
92− acc = f(arr[i])(acc);
98+ acc = A2(f, arr[i], acc);
94 return acc;
100 return acc;
97 function foldl1(f, xs) {
103 function foldl1(f, xs) {
98− return xs.ctor === "Nil" ? throwError('foldl1') : foldl(f, xs._0, xs._1);
104+ return xs === Nil ? throwError('foldl1') : foldl(f, xs._0, xs._1);
101 function foldr1(f, xs) {
107 function foldr1(f, xs) {
102− if (xs.ctor === "Nil") { throwError('foldr1'); }
108+ if (xs === Nil) { throwError('foldr1'); }
103 var arr = toArray(xs);
109 var arr = toArray(xs);
104 var acc = arr.pop();
110 var acc = arr.pop();
105 for (var i = arr.length; i--; ) {
111 for (var i = arr.length; i--; ) {
@@ -117,14 +123,14 @@ Elm.Native.List = function(elm) {
118 return fromArray(arr);
124 return fromArray(arr);
121 function scanl1(f, xs) {
127 function scanl1(f, xs) {
122− return xs.ctor === "Nil" ? throwError('scanl1') : scanl(f, xs._0, xs._1);
128+ return xs === Nil ? throwError('scanl1') : scanl(f, xs._0, xs._1);
125 function filter(pred, xs) {
131 function filter(pred, xs) {
126 var arr = [];
132 var arr = [];
127− while (xs.ctor === "Cons") {
133+ while (xs !== Nil) {
128 if (pred(xs._0)) { arr.push(xs._0); }
134 if (pred(xs._0)) { arr.push(xs._0); }
129 xs = xs._1;
135 xs = xs._1;
@@ -133,7 +139,7 @@ Elm.Native.List = function(elm) {
134 function length(xs) {
140 function length(xs) {
135 var out = 0;
141 var out = 0;
136− while (xs.ctor === "Cons") {
142+ while (xs !== Nil) {
137 out += 1;
143 out += 1;
138 xs = xs._1;
144 xs = xs._1;
@@ -141,8 +147,7 @@ Elm.Native.List = function(elm) {
143 function member(x, xs) {
149 function member(x, xs) {
145− while (xs.ctor === "Cons") {
150+ while (xs !== Nil) {
146 if (Utils.eq(x,xs._0)) return true;
151 if (Utils.eq(x,xs._0)) return true;
147 xs = xs._1;
152 xs = xs._1;
@@ -152,7 +157,7 @@ Elm.Native.List = function(elm) {
152 function reverse(xs) { return fromArray(toArray(xs).reverse()); }
157 function reverse(xs) { return fromArray(toArray(xs).reverse()); }
154 function concat(xss) {
159 function concat(xss) {
155− if (xss.ctor === 'Nil') return xss;
160+ if (xss === Nil) return xss;
156 var arr = toArray(xss);
161 var arr = toArray(xss);
157 var xs = arr[arr.length-1];
162 var xs = arr[arr.length-1];
158 for (var i = arr.length-1; i--; ) {
163 for (var i = arr.length-1; i--; ) {
@@ -160,9 +165,9 @@ Elm.Native.List = function(elm) {
161 return xs;
166 return xs;
164 function all(pred, xs) {
169 function all(pred, xs) {
165− while (xs.ctor === "Cons") {
170+ while (xs !== Nil) {
166 if (!pred(xs._0)) return false;
171 if (!pred(xs._0)) return false;
167 xs = xs._1;
172 xs = xs._1;
@@ -170,7 +175,7 @@ Elm.Native.List = function(elm) {
172 function any(pred, xs) {
177 function any(pred, xs) {
173− while (xs.ctor === "Cons") {
178+ while (xs !== Nil) {
174 if (pred(xs._0)) return true;
179 if (pred(xs._0)) return true;
175 xs = xs._1;
180 xs = xs._1;
@@ -179,7 +184,7 @@ Elm.Native.List = function(elm) {
180 function zipWith(f, xs, ys) {
185 function zipWith(f, xs, ys) {
181 var arr = [];
186 var arr = [];
182− while (xs.ctor === "Cons" && ys.ctor === "Cons") {
187+ while (xs !== Nil && ys !== Nil) {
183 arr.push(A2(f, xs._0, ys._0));
188 arr.push(A2(f, xs._0, ys._0));
184 xs = xs._1;
189 xs = xs._1;
185 ys = ys._1;
190 ys = ys._1;
@@ -189,7 +194,7 @@ Elm.Native.List = function(elm) {
190 function zip(xs, ys) {
195 function zip(xs, ys) {
191 var arr = [];
196 var arr = [];
192− while (xs.ctor === "Cons" && ys.ctor === "Cons") {
197+ while (xs !== Nil && ys !== Nil) {
193 arr.push(Utils.Tuple2(xs._0, ys._0));
198 arr.push(Utils.Tuple2(xs._0, ys._0));
194 xs = xs._1;
199 xs = xs._1;
195 ys = ys._1;
200 ys = ys._1;
@@ -199,15 +204,15 @@ Elm.Native.List = function(elm) {
200 function sort(xs) {
205 function sort(xs) {
201 function cmp(a,b) {
206 function cmp(a,b) {
202− var ord = Utils.compare(a,b);
207+ var ord = Utils.compare(a,b).ctor;
203− return ord === 'EQ' ? 0 : ord === 'LT' ? -1 : 1;
208+ return ord=== 'EQ' ? 0 : ord === 'LT' ? -1 : 1;
205 return fromArray(toArray(xs).sort(cmp));
210 return fromArray(toArray(xs).sort(cmp));
208 function take(n, xs) {
213 function take(n, xs) {
209 var arr = [];
214 var arr = [];
210− while (xs.ctor === "Cons" && n > 0) {
215+ while (xs !== Nil && n > 0) {
211 arr.push(xs._0);
216 arr.push(xs._0);
212 xs = xs._1;
217 xs = xs._1;
@@ -216,7 +221,7 @@ Elm.Native.List = function(elm) {
218 function drop(n, xs) {
223 function drop(n, xs) {
219− while (xs.ctor === "Cons" && n > 0) {
224+ while (xs !== Nil && n > 0) {
220 xs = xs._1;
225 xs = xs._1;
@@ -224,11 +229,11 @@ Elm.Native.List = function(elm) {
226 function join(sep, xss) {
231 function join(sep, xss) {
227− if (xss.ctor === 'Nil') return {ctor:'Nil'}
232+ if (xss === Nil) return Nil;
228 var s = toArray(sep);
233 var s = toArray(sep);
229 var out = toArray(xss._0);
234 var out = toArray(xss._0);
230 xss = xss._1;
235 xss = xss._1;
231− while (xss.ctor === "Cons") {
236+ while (xss !== Nil) {
232 out = out.concat(s, toArray(xss._0));
237 out = out.concat(s, toArray(xss._0));
233 xss = xss._1;
238 xss = xss._1;
@@ -236,37 +241,37 @@ Elm.Native.List = function(elm) {
238 function split(sep, xs) {
243 function split(sep, xs) {
239− var out = {ctor:'Nil'};
244+ var out = Nil;
240 var array = toArray(xs);
245 var array = toArray(xs);
241 var s = toArray(sep);
246 var s = toArray(sep);
242 var slen = s.length;
247 var slen = s.length;
243 if (slen === 0) {
248 if (slen === 0) {
244 for (var i = array.length; i--; ) {
249 for (var i = array.length; i--; ) {
245− out = Cons(Cons(array[i],Nil), out);
250+ out = Cons(Cons(array[i],Nil), out);
247 return out;
252 return out;
249− var temp = {ctor:'Nil'};
254+ var temp = Nil;
250 for (var i = array.length - slen; i >= 0; --i) {
255 for (var i = array.length - slen; i >= 0; --i) {
251 var match = true;
256 var match = true;
252 for (var j = slen; j--; ) {
257 for (var j = slen; j--; ) {
253− if (!Utils.eq(array[i+j], s[j])) { match = false; break; }
258+ if (!Utils.eq(array[i+j], s[j])) { match = false; break; }
255 if (match) {
260 if (match) {
256− out = {ctor:'Cons', _0:temp, _1:out};
261+ out = Cons(temp,out);
257− temp = {ctor:'Nil'};
262+ temp = Nil;
258− i -= slen - 1;
263+ i -= slen - 1;
260− temp = {ctor:'Cons', _0:array[i+j], _1:temp};
265+ temp = Cons(array[i+j], temp);
263 for (var j = slen-1; j--; ) {
268 for (var j = slen-1; j--; ) {
264− temp = {ctor:'Cons', _0:array[j], _1:temp};
269+ temp = Cons(array[j], temp);
266− out = {ctor:'Cons', _0:temp, _1:out};
271+ out = Cons(temp, out);
267 return out;
272 return out;
270 return elm.Native.List = {
275 return elm.Native.List = {
272 Cons:Cons,
277 Cons:Cons,