@@ -7,7 +7,11 @@ Elm.Native.List = function(elm) {
77
88 var Utils = Elm.Native.Utils(elm);
99
10− var Nil = { ctor:'Nil' };
10+ // freeze is universally supported and as a singleton introduces little performance penalty
11+ // for a small amount of object safety
12+ var Nil = Object.freeze({ ctor:'Nil' });
13+
14+ // using freeze for every cons would be nice but is a huge (9x on firefox 19) performance penalty
1115 function Cons(hd,tl) { return { ctor:"Cons", _0:hd, _1:tl }; }
1216
1317 function throwError(f) {
@@ -16,13 +20,13 @@ Elm.Native.List = function(elm) {
1620
1721 function toArray(xs) {
1822 var out = [];
19− while (xs.ctor === "Cons") {
23+ while (xs !== Nil) {
2024 out.push(xs._0);
2125 xs = xs._1;
2226 }
2327 return out;
2428 }
25−
29+
2630 function fromArray(arr) {
2731 var out = Nil;
2832 for (var i = arr.length; i--; ) {
@@ -41,11 +45,11 @@ Elm.Native.List = function(elm) {
4145
4246 function append(xs,ys) {
4347 if (typeof xs === "string") { return xs.concat(ys); }
44− if (xs.ctor === "Nil") { return ys; }
48+ if (xs === Nil) { return ys; }
4549 var root = Cons(xs._0. Nil);
4650 var curr = root;
4751 xs = xs._1;
48− while (xs.ctor==="Cons") {
52+ while (xs !== Nil) {
4953 curr._1 = Cons(xs._0. Nil);
5054 xs = xs._1;
5155 curr = curr._1;
@@ -54,13 +58,13 @@ Elm.Native.List = function(elm) {
5458 return root;
5559 }
5660
57− function head(v) { return v.ctor === "Nil" ? throwError('head') : v._0; }
58− function tail(v) { return v.ctor === "Nil" ? throwError('tail') : v._1; }
61+ function head(v) { return v === Nil ? throwError('head') : v._0; }
62+ function tail(v) { return v === Nil ? throwError('tail') : v._1; }
5963
6064 function last(xs) {
61− if (xs.ctor === "Nil") { throwError('last'); }
65+ if (xs === Nil) { throwError('last'); }
6266 var out = xs._0;
63− while (xs.ctor === "Cons") {
67+ while (xs !== Nil) {
6468 out = xs._0;
6569 xs = xs._1;
6670 }
@@ -69,17 +73,19 @@ Elm.Native.List = function(elm) {
6973
7074 function map(f, xs) {
7175 var arr = [];
72− while (xs.ctor === "Cons") {
76+ while (xs !== Nil) {
7377 arr.push(f(xs._0));
7478 xs = xs._1;
7579 }
7680 return fromArray(arr);
7781 }
7882
83+ // f defined similarly for both foldl and foldr (NB: different from Haskell)
84+ // ie, foldl :: (a -> b -> b) -> b -> [a] -> b
7985 function foldl(f, b, xs) {
8086 var acc = b;
81− while (xs.ctor === "Cons") {
82− acc = f(xs._0)(acc);
87+ while (xs !== Nil) {
88+ acc = A2(f, xs._0, acc);
8389 xs = xs._1;
8490 }
8591 return acc;
@@ -89,17 +95,17 @@ Elm.Native.List = function(elm) {
8995 var arr = toArray(xs);
9096 var acc = b;
9197 for (var i = arr.length; i--; ) {
92− acc = f(arr[i])(acc);
98+ acc = A2(f, arr[i], acc);
9399 }
94100 return acc;
95101 }
96102
97103 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);
99105 }
100106
101107 function foldr1(f, xs) {
102− if (xs.ctor === "Nil") { throwError('foldr1'); }
108+ if (xs === Nil) { throwError('foldr1'); }
103109 var arr = toArray(xs);
104110 var acc = arr.pop();
105111 for (var i = arr.length; i--; ) {
@@ -117,14 +123,14 @@ Elm.Native.List = function(elm) {
117123 }
118124 return fromArray(arr);
119125 }
120−
126+
121127 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);
123129 }
124130
125131 function filter(pred, xs) {
126132 var arr = [];
127− while (xs.ctor === "Cons") {
133+ while (xs !== Nil) {
128134 if (pred(xs._0)) { arr.push(xs._0); }
129135 xs = xs._1;
130136 }
@@ -133,7 +139,7 @@ Elm.Native.List = function(elm) {
133139
134140 function length(xs) {
135141 var out = 0;
136− while (xs.ctor === "Cons") {
142+ while (xs !== Nil) {
137143 out += 1;
138144 xs = xs._1;
139145 }
@@ -141,8 +147,7 @@ Elm.Native.List = function(elm) {
141147 }
142148
143149 function member(x, xs) {
144− var out = 0;
145− while (xs.ctor === "Cons") {
150+ while (xs !== Nil) {
146151 if (Utils.eq(x,xs._0)) return true;
147152 xs = xs._1;
148153 }
@@ -152,7 +157,7 @@ Elm.Native.List = function(elm) {
152157 function reverse(xs) { return fromArray(toArray(xs).reverse()); }
153158
154159 function concat(xss) {
155− if (xss.ctor === 'Nil') return xss;
160+ if (xss === Nil) return xss;
156161 var arr = toArray(xss);
157162 var xs = arr[arr.length-1];
158163 for (var i = arr.length-1; i--; ) {
@@ -160,9 +165,9 @@ Elm.Native.List = function(elm) {
160165 }
161166 return xs;
162167 }
163−
168+
164169 function all(pred, xs) {
165− while (xs.ctor === "Cons") {
170+ while (xs !== Nil) {
166171 if (!pred(xs._0)) return false;
167172 xs = xs._1;
168173 }
@@ -170,7 +175,7 @@ Elm.Native.List = function(elm) {
170175 }
171176
172177 function any(pred, xs) {
173− while (xs.ctor === "Cons") {
178+ while (xs !== Nil) {
174179 if (pred(xs._0)) return true;
175180 xs = xs._1;
176181 }
@@ -179,7 +184,7 @@ Elm.Native.List = function(elm) {
179184
180185 function zipWith(f, xs, ys) {
181186 var arr = [];
182− while (xs.ctor === "Cons" && ys.ctor === "Cons") {
187+ while (xs !== Nil && ys !== Nil) {
183188 arr.push(A2(f, xs._0, ys._0));
184189 xs = xs._1;
185190 ys = ys._1;
@@ -189,7 +194,7 @@ Elm.Native.List = function(elm) {
189194
190195 function zip(xs, ys) {
191196 var arr = [];
192− while (xs.ctor === "Cons" && ys.ctor === "Cons") {
197+ while (xs !== Nil && ys !== Nil) {
193198 arr.push(Utils.Tuple2(xs._0, ys._0));
194199 xs = xs._1;
195200 ys = ys._1;
@@ -199,15 +204,15 @@ Elm.Native.List = function(elm) {
199204
200205 function sort(xs) {
201206 function cmp(a,b) {
202− var ord = Utils.compare(a,b);
203− return ord === 'EQ' ? 0 : ord === 'LT' ? -1 : 1;
207+ var ord = Utils.compare(a,b).ctor;
208+ return ord=== 'EQ' ? 0 : ord === 'LT' ? -1 : 1;
204209 }
205210 return fromArray(toArray(xs).sort(cmp));
206211 }
207−
212+
208213 function take(n, xs) {
209214 var arr = [];
210− while (xs.ctor === "Cons" && n > 0) {
215+ while (xs !== Nil && n > 0) {
211216 arr.push(xs._0);
212217 xs = xs._1;
213218 --n;
@@ -216,7 +221,7 @@ Elm.Native.List = function(elm) {
216221 }
217222
218223 function drop(n, xs) {
219− while (xs.ctor === "Cons" && n > 0) {
224+ while (xs !== Nil && n > 0) {
220225 xs = xs._1;
221226 --n;
222227 }
@@ -224,11 +229,11 @@ Elm.Native.List = function(elm) {
224229 }
225230
226231 function join(sep, xss) {
227− if (xss.ctor === 'Nil') return {ctor:'Nil'}
232+ if (xss === Nil) return Nil;
228233 var s = toArray(sep);
229234 var out = toArray(xss._0);
230235 xss = xss._1;
231− while (xss.ctor === "Cons") {
236+ while (xss !== Nil) {
232237 out = out.concat(s, toArray(xss._0));
233238 xss = xss._1;
234239 }
@@ -236,37 +241,37 @@ Elm.Native.List = function(elm) {
236241 }
237242
238243 function split(sep, xs) {
239− var out = {ctor:'Nil'};
244+ var out = Nil;
240245 var array = toArray(xs);
241246 var s = toArray(sep);
242247 var slen = s.length;
243248 if (slen === 0) {
244249 for (var i = array.length; i--; ) {
245− out = Cons(Cons(array[i],Nil), out);
250+ out = Cons(Cons(array[i],Nil), out);
246251 }
247252 return out;
248253 }
249− var temp = {ctor:'Nil'};
254+ var temp = Nil;
250255 for (var i = array.length - slen; i >= 0; --i) {
251256 var match = true;
252257 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; }
254259 }
255260 if (match) {
256− out = {ctor:'Cons', _0:temp, _1:out};
257− temp = {ctor:'Nil'};
258− i -= slen - 1;
261+ out = Cons(temp,out);
262+ temp = Nil;
263+ i -= slen - 1;
259264 } else {
260− temp = {ctor:'Cons', _0:array[i+j], _1:temp};
265+ temp = Cons(array[i+j], temp);
261266 }
262267 }
263268 for (var j = slen-1; j--; ) {
264− temp = {ctor:'Cons', _0:array[j], _1:temp};
269+ temp = Cons(array[j], temp);
265270 }
266− out = {ctor:'Cons', _0:temp, _1:out};
271+ out = Cons(temp, out);
267272 return out;
268273 }
269−
274+
270275 return elm.Native.List = {
271276 Nil:Nil,
272277 Cons:Cons,