on master help sign in
Merge pull request #546 from Xashili/array

Array

commitad5bdaab95e72d7df8ff866525a6593a86f4feab authorEvan Czaplicki <info@elm-lang.org> dateMon 31 Mar 2014, 16:11 (13 years ago) parent3d40a4fa61faef
3 files changed+197−191
libraries/Array.elm+30−31 libraries/Native/Array.js+163−160 libraries/Native/Show.js+4
libraries/Array.elm+30−31
@@ -8,16 +8,16 @@ If you use more then one map or zip function on an array, consider turning it
88into a list before operating on it, and then turning it back into an array.
99
1010# Basics
11−@docs empty, length, get, safeGet, getWithDefault
11+@docs empty, length, get, getMaybe, getSafe
1212
1313# Putting Arrays Together
1414@docs fill, fromList, concat, set, updates, push
1515
1616# Taking Arrays Apart
17−@docs elements, indices, assocs, slice
17+@docs toList, toIndexedList, indices, slice
1818
1919# Mapping, folding, zipping
20−@docs map, assocMap, foldl, foldr, zip, zipWith
20+@docs map, indexedMap, foldl, foldr, zip, zipWith
2121-}
2222
2323import Native.Array
@@ -34,16 +34,17 @@ data Array a = Array
3434fill : Int -> a -> Array a
3535fill len e = fromList <| List.map (always e) [1..len]
3636
37+-- TODO: make this a native function.
3738{-| Create an array from a list. -}
3839fromList : [a] -> Array a
3940fromList = List.foldl (Native.Array.push) Native.Array.empty
4041
4142{-| Create a list of elements from an array.
4243
43− elements (fromList [3,5,8]) == [3,5,8]
44+ toList (fromList [3,5,8]) == [3,5,8]
4445-}
45−elements : Array a -> [a]
46−elements = Native.Array.toList
46+toList : Array a -> [a]
47+toList = Native.Array.toList
4748
4849{-| Create a list of the possible indices of an array.
4950
@@ -52,12 +53,13 @@ elements = Native.Array.toList
5253indices : Array a -> [Int]
5354indices a = [0..Native.Array.length a - 1]
5455
56+-- TODO: make this a native function.
5557{-| Create a list of tuples (Index, Element) from an array.
5658
57− assocs (fromList [3,5,8]) == [(0,3), (1,5), (2,8)]
59+ toIndexedList (fromList [3,5,8]) == [(0,3), (1,5), (2,8)]
5860-}
59−assocs : Array a -> [(Int, a)]
60−assocs a = List.zip (indices a) (Native.Array.elements a)
61+toIndexedList : Array a -> [(Int, a)]
62+toIndexedList a = List.zip (indices a) (Native.Array.toList a)
6163
6264{-| Apply a function on every element in an array.
6365
@@ -66,12 +68,12 @@ assocs a = List.zip (indices a) (Native.Array.elements a)
6668map : (a -> b) -> Array a -> Array b
6769map = Native.Array.map
6870
69−{-| Apply a function with an index on every element in an array.
71+{-| Apply a function on every element with its index as first argument.
7072
71− assocMap (*) (fromList [5,5,5]) == fromList [0,5,10]
73+ indexedMap (*) (fromList [5,5,5]) == fromList [0,5,10]
7274-}
73−assocMap : (Int -> a -> b) -> Array a -> Array b
74−assocMap = Native.Array.assocMap
75+indexedMap : (Int -> a -> b) -> Array a -> Array b
76+indexedMap = Native.Array.indexedMap
7577
7678{-| Reduce an array from the left.
7779
@@ -102,7 +104,7 @@ is longer, the extra elements are dropped.
102104-}
103105zipWith : (a -> b -> c) -> Array a -> Array b -> Array c
104106zipWith f a b =
105− fromList <| List.zipWith f (Native.Array.elements a) (Native.Array.elements b)
107+ fromList <| List.zipWith f (Native.Array.toList a) (Native.Array.toList b)
106108
107109{-| Return an empty array.
108110
@@ -126,28 +128,25 @@ array length is unkown, use safeGet oder getWithDefault.
126128get : Int -> Array a -> a
127129get = Native.Array.get
128130
129−{-| Return Just the element at the index or Nothing.
131+{-| Return Just the element at the index or Nothing if the index is out of range.
130132
131− safeGet 2 (A.fromList [3,2,1]) == Just 2
132− safeGet 5 (A.fromList [3,2,1]) == Nothing
133+ getMaybe 2 (A.fromList [3,2,1]) == Just 2
134+ getMaybe 5 (A.fromList [3,2,1]) == Nothing
133135-}
134−safeGet : Int -> Array a -> Maybe a
135−safeGet i array =
136− if i < Native.Array.length array
137− then Just (Native.Array.get i array)
138− else Nothing
136+getMaybe : Int -> Array a -> Maybe a
137+getMaybe i array = if Native.Array.length array > i
138+ then Just (Native.Array.get i array)
139+ else Nothing
139140
140141{-| Get the element at the index. If the index is out of range, the given default
141−elementis returned.
142+element is returned.
142143
143− getWithDefault 0 2 (A.fromList [3,2,1]) == 1
144− getWithDefault 0 5 (A.fromList [3,2,1]) == 0
144+ getSafe 0 2 (A.fromList [3,2,1]) == 1
145+ getSafe 0 5 (A.fromList [3,2,1]) == 0
145146-}
146−getWithDefault : a -> Int -> Array a -> a
147−getWithDefault default i array =
148− if i < Native.Array.length array
149− then Native.Array.get i array
150− else default
147+getSafe : a -> Int -> Array a -> a
148+getSafe default i array = if Native.Array.length array > i
149+ then Native.Array.get i array else default
151150
152151{-| Set the element at the index. Returns the updated array, or if the index is
153152out of range, the unaltered array.
@@ -162,7 +161,7 @@ set = Native.Array.set
162161 updates [(1,7),(2,8)] (fill 3 1) == fromList [1,7,8]
163162-}
164163updates : [(Int, a)] -> Array a -> Array a
165−updates assocs array = List.foldl (uncurry Native.Array.set) array assocs
164+updates us array = List.foldl (uncurry Native.Array.set) array us
166165
167166{-| Slice an array given a range. The selection is inclusive, so the last
168167element in the selection will also be in the new array. This may change in the
libraries/Native/Array.js+163−160
@@ -8,33 +8,35 @@ Elm.Native.Array.make = function(elm) {
88
99 var List = Elm.Native.List.make(elm);
1010
11− // An RRB-Tree has two distinct data types. A leaf which contains data as
12− // an array in _1, and a height in _0, that is always 0. A node has in
13− // addition its size table in _2, while _1 contains an array of nodes or
14− // leaves.
15−
16− // M is the maximal node size. 32 seems fast. E is the allowed increase
11+ // A RRB-Tree has two distinct data types.
12+ // Leaf -> "height" is always 0
13+ // "table" is an array of elements
14+ // Node -> "height" is always greater than 0
15+ // "table" is an array of child nodes
16+ // "lengths" is an array of accumulated lengths of the child nodes
17+
18+ // M is the maximal table size. 32 seems fast. E is the allowed increase
1719 // of search steps when concatting to find an index. Lower values will
1820 // decrease balancing, but will increase search steps.
1921 var M = 32;
2022 var E = 2;
2123
2224 // An empty array.
23− var empty = { ctor:"_Array", _0:0, _1:new Array() };
25+ var empty = { ctor:"_Array", height:0, table:new Array() };
2426
2527 // Gets the value at index i recursively.
2628 function get(i, a) {
27− if (a._0 == 0) {
28− if (i < a._1.length) {
29− return a._1[i];
29+ if (a.height == 0) {
30+ if (i < a.table.length) {
31+ return a.table[i];
3032 } else {
31− throw new Error("Index "+ i +" on the array is out of range. Check the length first or you safeGet.");
33+ throw new Error("Index "+ i +" is out of range. Check the length of your array first or use getSafe or getMaybe.");
3234 }
3335 }
3436
3537 var slot = getSlot(i, a);
36− var sub = slot > 0 ? a._2[slot-1] : 0;
37− return get(i - sub, a._1[slot]);
38+ var sub = slot > 0 ? a.lengths[slot-1] : 0;
39+ return get(i - sub, a.table[slot]);
3840 }
3941
4042 // Sets the value at the index i. Only the nodes leading to i will get
@@ -44,14 +46,14 @@ Elm.Native.Array.make = function(elm) {
4446 return a;
4547 }
4648 var newA = nodeCopy(a);
47− newA._1 = a._1.slice();
49+ newA.table = a.table.slice();
4850
49− if (a._0 == 0) {
50− newA._1[i] = item;
51+ if (a.height == 0) {
52+ newA.table[i] = item;
5153 } else {
5254 var slot = getSlot(i, a);
53− var sub = slot > 0 ? a._2[slot-1] : 0;
54− newA._1[slot] = set(i - sub, item, a._1[slot]);
55+ var sub = slot > 0 ? a.lengths[slot-1] : 0;
56+ newA.table[slot] = set(i - sub, item, a.table[slot]);
5557 }
5658 return newA;
5759 }
@@ -63,7 +65,7 @@ Elm.Native.Array.make = function(elm) {
6365 return pushed;
6466 }
6567
66− newTree = create(item, a._0);
68+ newTree = create(item, a.height);
6769 return siblise(a, newTree);
6870 }
6971
@@ -72,10 +74,10 @@ Elm.Native.Array.make = function(elm) {
7274 // null will be returned.
7375 function push_(item, a) {
7476 // Handle resursion stop at leaf level.
75− if (a._0 == 0) {
76− if (a._1.length < M) {
77− var newA = { ctor:"_Array", _0:0, _1:a._1.slice() };
78− newA._1.push(item);
77+ if (a.height == 0) {
78+ if (a.table.length < M) {
79+ var newA = { ctor:"_Array", height:0, table:a.table.slice() };
80+ newA.table.push(item);
7981 return newA;
8082 } else {
8183 return null;
@@ -89,19 +91,19 @@ Elm.Native.Array.make = function(elm) {
8991 // be updated.
9092 if (pushed != null) {
9193 var newA = nodeCopy(a);
92− newA._1[newA._1.length - 1] = pushed;
93− newA._2[newA._2.length - 1]++;
94+ newA.table[newA.table.length - 1] = pushed;
95+ newA.lengths[newA.lengths.length - 1]++;
9496 return newA
9597 }
9698
9799 // When there was no space left, check if there is space left
98100 // for a new slot with a tree which contains only the item
99101 // at the bottom.
100− if (a._1.length < M) {
101− var newSlot = create(item, a._0 - 1);
102+ if (a.table.length < M) {
103+ var newSlot = create(item, a.height - 1);
102104 var newA = nodeCopy(a);
103− newA._1.push(newSlot);
104− newA._2.push(newA._2[newA._2.length - 1] + length(newSlot));
105+ newA.table.push(newSlot);
106+ newA.lengths.push(newA.lengths[newA.lengths.length - 1] + length(newSlot));
105107 return newA
106108 } else {
107109 return null;
@@ -109,53 +111,54 @@ Elm.Native.Array.make = function(elm) {
109111 }
110112
111113 // Converts an array into a list of elements.
112− function elements(a) {
113− return elements_(List.Nil, a);
114+ function toList(a) {
115+ return toList_(List.Nil, a);
114116 }
115117
116− function elements_(list, a) {
117− for (var i = a._1.length - 1; i >= 0; i--) {
118− list = a._0 == 0 ? List.Cons(a._1[i], list) : elements_(list, a._1[i]);
118+ function toList_(list, a) {
119+ for (var i = a.table.length - 1; i >= 0; i--) {
120+ list = a.height == 0 ? List.Cons(a.table[i], list) : toList_(list, a.table[i]);
119121 }
120122 return list;
121123 }
122124
123− // Maps a function over an array.
125+ // Maps a function over the elements of an array.
124126 function map(f, a) {
125− var newA = { ctor:"_Array", _0:a._0, _1:new Array(a._1) };
126− if (a._0 > 0) { newA._2 = a._2; }
127− for (var i = 0; i < a._1.length; i++) {
128− newA._1[i] = a._0 == 0 ? f(a._1[i]) : map(f, a._1[i]);
127+ var newA = { ctor:"_Array", height:a.height, table:new Array(a.table) };
128+ if (a.height > 0) { newA.lengths = a.lengths; }
129+ for (var i = 0; i < a.table.length; i++) {
130+ newA.table[i] = a.height == 0 ? f(a.table[i]) : map(f, a.table[i]);
129131 }
130132 return newA;
131133 }
132134
133− function assocMap(f, a) {
134− var newA = { ctor:"_Array", _0:a._0, _1:new Array(a._1) };
135− if (a._0 > 0) { newA._2 = a._2; }
136− for (var i = 0; i < a._1.length; i++) {
137− newA._1[i] = a._0 == 0 ? A2(f, i, a._1[i]) : assocMap(f, a._1[i]);
135+ // Maps a function over the elements with their index as first argument.
136+ function indexedMap(f, a) {
137+ var newA = { ctor:"_Array", height:a.height, table:new Array(a.table) };
138+ if (a.height > 0) { newA.lengths = a.lengths; }
139+ for (var i = 0; i < a.table.length; i++) {
140+ newA.table[i] = a.height == 0 ? A2(f, i, a.table[i]) : indexedMap(f, a.table[i]);
138141 }
139142 return newA;
140143 }
141144
142145 function foldl(f, b, a) {
143− for (var i = a._1.length - 1; i >= 0; i--) {
144− b = A2(f, a._0 == 0 ? a._1[i] : foldl(f, b, a._1[i]), b);
146+ for (var i = a.table.length - 1; i >= 0; i--) {
147+ b = A2(f, a.height == 0 ? a.table[i] : foldl(f, b, a.table[i]), b);
145148 }
146149 return b;
147150 }
148151
149152 function foldr(f, b, a) {
150− for (var i = 0; i < a._1.length; i++) {
151− b = A2(f, a._0 == 0 ? a._1[i] : foldr(f, b, a._1[i]), b);
153+ for (var i = 0; i < a.table.length; i++) {
154+ b = A2(f, a.height == 0 ? a.table[i] : foldr(f, b, a.table[i]), b);
152155 }
153156 return b;
154157 }
155158
156− // Returns a sliced tree. The to is inclusive, but this may change,
159+ // Returns a sliced tree. "to" is inclusive, but this may change,
157160 // when I understand, why e.g. JS does not handle it this way. :-)
158− // If from or to is negative, they will select from the end on.
161+ // If "from" or "to" is negative, they will select from the end on.
159162 // TODO: currently, it slices the right, then the left. This can be
160163 // optimized.
161164 function slice(from, to, a) {
@@ -170,15 +173,15 @@ Elm.Native.Array.make = function(elm) {
170173 }
171174
172175 // Handle leaf level.
173− if (a._0 == 0) {
174− var newA = { ctor:"_Array", _0:0 };
175− newA._1 = a._1.slice(0, to + 1);
176+ if (a.height == 0) {
177+ var newA = { ctor:"_Array", height:0 };
178+ newA.table = a.table.slice(0, to + 1);
176179 return newA;
177180 }
178181
179182 // Slice the right recursively.
180183 var right = getSlot(to, a);
181− var sliced = sliceRight(to - (right > 0 ? a._2[right - 1] : 0), a._1[right]);
184+ var sliced = sliceRight(to - (right > 0 ? a.lengths[right - 1] : 0), a.table[right]);
182185
183186 // Maybe the a node is not even needed, as sliced contains the whole slice.
184187 if (right == 0) {
@@ -186,11 +189,11 @@ Elm.Native.Array.make = function(elm) {
186189 }
187190
188191 // Create new node.
189− var newA = { ctor:"_Array", _0:a._0
190− , _1:a._1.slice(0, right + 1)
191− , _2:a._2.slice(0, right + 1) };
192− newA._1[right] = sliced;
193− newA._2[right] = length(sliced) + (right > 0 ? newA._2[right - 1] : 0);
192+ var newA = { ctor:"_Array", height:a.height
193+ , table:a.table.slice(0, right + 1)
194+ , lengths:a.lengths.slice(0, right + 1) };
195+ newA.table[right] = sliced;
196+ newA.lengths[right] = length(sliced) + (right > 0 ? newA.lengths[right - 1] : 0);
194197 return newA;
195198 }
196199
@@ -200,30 +203,30 @@ Elm.Native.Array.make = function(elm) {
200203 }
201204
202205 // Handle leaf level.
203− if (a._0 == 0) {
204− var newA = { ctor:"_Array", _0:0 };
205− newA._1 = a._1.slice(from, a._1.length + 1);
206+ if (a.height == 0) {
207+ var newA = { ctor:"_Array", height:0 };
208+ newA.table = a.table.slice(from, a.table.length + 1);
206209 return newA;
207210 }
208211
209212 // Slice the left recursively.
210213 var left = getSlot(from, a);
211− var sliced = sliceLeft(from - (left > 0 ? a._2[left - 1] : 0), a._1[left]);
214+ var sliced = sliceLeft(from - (left > 0 ? a.lengths[left - 1] : 0), a.table[left]);
212215
213216 // Maybe the a node is not even needed, as sliced contains the whole slice.
214− if (left == a._1.length - 1) {
217+ if (left == a.table.length - 1) {
215218 return sliced;
216219 }
217220
218221 // Create new node.
219− var newA = { ctor:"_Array", _0:a._0
220− , _1:a._1.slice(left, a._1.length + 1)
221− , _2:new Array(a._1.length - left) };
222− newA._1[left] = sliced;
222+ var newA = { ctor:"_Array", height:a.height
223+ , table:a.table.slice(left, a.table.length + 1)
224+ , lengths:new Array(a.table.length - left) };
225+ newA.table[left] = sliced;
223226 var len = 0;
224− for (var i = 0; i < newA._1.length; i++) {
225− len += length(newA._1[i]);
226− newA._2[i] = len;
227+ for (var i = 0; i < newA.table.length; i++) {
228+ len += length(newA.table[i]);
229+ newA.lengths[i] = len;
227230 }
228231
229232 return newA;
@@ -233,12 +236,12 @@ Elm.Native.Array.make = function(elm) {
233236 // TODO: Add support for concatting trees of different sizes. Current
234237 // behavior will just rise the lower tree and then concat them.
235238 function concat(a, b) {
236− if (b._0 > a._0) { return concat(parentise(a, b._0), b); }
237− if (a._0 > b._0) { return concat(a, parentise(b, a._0)); }
238− if (a._0 == 0) { return concat(parentise(a, 1), parentise(b, 1)); }
239+ if (b.height > a.height) { return concat(parentise(a, b.height), b); }
240+ if (a.height > b.height) { return concat(a, parentise(b, a.height)); }
241+ if (a.height == 0) { return concat(parentise(a, 1), parentise(b, 1)); }
239242
240243 var c = concat_(a, b);
241− if (c[1]._1.length > 0) {
244+ if (c[1].table.length > 0) {
242245 return siblise(c[0], c[1]);
243246 } else {
244247 return c[0];
@@ -249,7 +252,7 @@ Elm.Native.Array.make = function(elm) {
249252 // needs to be handled by the function, that called concat_. May be only
250253 // called for trees with an minimal height of 1.
251254 function concat_(a, b) {
252− if (a._0 == 1) {
255+ if (a.height == 1) {
253256 // Check if balancing is needed and return based on that.
254257 var toRemove = calcToRemove(a, b);
255258 if (toRemove <= E) {
@@ -263,29 +266,29 @@ Elm.Native.Array.make = function(elm) {
263266 a = nodeCopy(a), b = nodeCopy(b);
264267
265268 // Adjust the bottom right side of the new tree.
266− a._1[a._1.length - 1] = concated[0];
267− a._2[a._2.length - 1] = length(concated[0])
268− a._2[a._2.length - 1] += a._2.length > 1 ? a._2[a._2.length - 2] : 0;
269+ a.table[a.table.length - 1] = concated[0];
270+ a.lengths[a.lengths.length - 1] = length(concated[0])
271+ a.lengths[a.lengths.length - 1] += a.lengths.length > 1 ? a.lengths[a.lengths.length - 2] : 0;
269272
270273 // Adjust the bottom left side of the new tree.
271− if (concated[1]._1.length > 0) {
272− b._1[0] = concated[1];
273− b._2[0] = length(concated[1]);
274− for (var i = 1, len = length(b._1[0]); i < b._2.length; i++) {
275− len += length(b._1[i]);
276− b._2[i] = len;
274+ if (concated[1].table.length > 0) {
275+ b.table[0] = concated[1];
276+ b.lengths[0] = length(concated[1]);
277+ for (var i = 1, len = length(b.table[0]); i < b.lengths.length; i++) {
278+ len += length(b.table[i]);
279+ b.lengths[i] = len;
277280 }
278281 } else {
279− b._1.shift();
280− for (var i = 1; i < b._2.length; i++) {
281− b._2[i] = b._2[i] - b._2[0];
282+ b.table.shift();
283+ for (var i = 1; i < b.lengths.length; i++) {
284+ b.lengths[i] = b.lengths[i] - b.lengths[0];
282285 }
283− b._2.shift();
286+ b.lengths.shift();
284287 }
285288
286289 // Check if balancing is needed and return based on that.
287290 var toRemove = calcToRemove(a, b);
288− if (toRemove <= E || b._1.length == 0) {
291+ if (toRemove <= E || b.table.length == 0) {
289292 return [a,b];
290293 }
291294
@@ -295,18 +298,18 @@ Elm.Native.Array.make = function(elm) {
295298 // Returns the extra search steps for E. Refer to the paper.
296299 function calcToRemove(a, b) {
297300 var subLengths = 0;
298− for (var i = 0; i < a._1.length; i++) {
299− subLengths += a._1[i]._1.length;
301+ for (var i = 0; i < a.table.length; i++) {
302+ subLengths += a.table[i].table.length;
300303 }
301− for (var i = 0; i < b._1.length; i++) {
302− subLengths += b._1[i]._1.length;
304+ for (var i = 0; i < b.table.length; i++) {
305+ subLengths += b.table[i].table.length;
303306 }
304307
305− var toRemove = a._1.length + b._1.length
308+ var toRemove = a.table.length + b.table.length
306309 return toRemove - (Math.floor((subLengths - 1) / M) + 1);
307310 }
308311
309− // get2 and set2 are helpers for accessing over two arrays.
312+ // get2, set2 and saveSlot are helpers for accessing elements over two arrays.
310313 function get2(a, b, index) {
311314 return index < a.length ? a[index] : b[index - a.length];
312315 }
@@ -319,59 +322,59 @@ Elm.Native.Array.make = function(elm) {
319322 }
320323 }
321324
325+ function saveSlot(a, b, index, slot) {
326+ set2(a.table, b.table, index, slot);
327+
328+ var l = (index == 0 || index == a.lengths.length) ?
329+ 0 : get2(a.lengths, a.lengths, index - 1);
330+ set2(a.lengths, b.lengths, index, l + length(slot));
331+ }
332+
322333 // Creates a node or leaf with a given length at their arrays for perfomance.
323334 // Is only used by shuffle.
324− function createNode(height, length) {
335+ function createNode(h, length) {
325336 if (length < 0) { length = 0; }
326− var a = { ctor:"_Array", _0:height, _1:new Array(length) };
327− if (height > 0) {
328− a._2 = new Array(length);
337+ var a = { ctor:"_Array", height:h, table:new Array(length) };
338+ if (h > 0) {
339+ a.lengths = new Array(length);
329340 }
330341 return a;
331342 }
332343
333− function saveSlot(a, b, index, slot) {
334− set2(a._1, b._1, index, slot);
335−
336− var l = (index == 0 || index == a._2.length) ?
337− 0 : get2(a._2, a._2, index - 1);
338− set2(a._2, b._2, index, l + length(slot));
339− }
340−
341344 // Returns an array of two balanced nodes.
342345 function shuffle(a, b, toRemove) {
343− var newA = createNode(a._0, Math.min(M, a._1.length + b._1.length - toRemove));
344− var newB = createNode(a._0, newA._1.length - (a._1.length + b._1.length - toRemove));
346+ var newA = createNode(a.height, Math.min(M, a.table.length + b.table.length - toRemove));
347+ var newB = createNode(a.height, newA.table.length - (a.table.length + b.table.length - toRemove));
345348
346349 // Skip the slots with size M. More precise: copy the slot references
347350 // to the new node
348351 var read = 0;
349− while (get2(a._1, b._1, read)._1.length % M == 0) {
350− set2(newA._1, newB._1, read, get2(a._1, b._1, read));
351− set2(newA._2, newB._2, read, get2(a._2, b._2, read));
352+ while (get2(a.table, b.table, read).table.length % M == 0) {
353+ set2(newA.table, newB.table, read, get2(a.table, b.table, read));
354+ set2(newA.lengths, newB.lengths, read, get2(a.lengths, b.lengths, read));
352355 read++;
353356 }
354357
355358 // Pulling items from left to right, caching in a slot before writing
356359 // it into the new nodes.
357360 var write = read;
358− var slot = new createNode(a._0 - 1, 0);
361+ var slot = new createNode(a.height - 1, 0);
359362 var from = 0;
360363
361364 // If the current slot is still containing data, then there will be at
362365 // least one more write, so we do not break this loop yet.
363− while (read - write - (slot._1.length > 0 ? 1 : 0) < toRemove) {
366+ while (read - write - (slot.table.length > 0 ? 1 : 0) < toRemove) {
364367 // Find out the max possible items for copying.
365− var source = get2(a._1, b._1, read);
366− var to = Math.min(M - slot._1.length, source._1.length)
368+ var source = get2(a.table, b.table, read);
369+ var to = Math.min(M - slot.table.length, source.table.length)
367370
368371 // Copy and adjust size table.
369− slot._1 = slot._1.concat(source._1.slice(from, to));
370− if (slot._0 > 0) {
371− var len = slot._2.length;
372+ slot.table = slot.table.concat(source.table.slice(from, to));
373+ if (slot.height > 0) {
374+ var len = slot.lengths.length;
372375 for (var i = len; i < len + to - from; i++) {
373− slot._2[i] = length(slot._1[i]);
374− slot._2[i] += (i > 0 ? slot._2[i - 1] : 0);
376+ slot.lengths[i] = length(slot.table[i]);
377+ slot.lengths[i] += (i > 0 ? slot.lengths[i - 1] : 0);
375378 }
376379 }
377380
@@ -379,60 +382,60 @@ Elm.Native.Array.make = function(elm) {
379382
380383 // Only proceed to next slots[i] if the current one was
381384 // fully copied.
382− if (source._1.length <= to) {
385+ if (source.table.length <= to) {
383386 read++; from = 0;
384387 }
385388
386389 // Only create a new slot if the current one is filled up.
387− if (slot._1.length == M) {
390+ if (slot.table.length == M) {
388391 saveSlot(newA, newB, write, slot);
389− slot = createNode(a._0 - 1,0);
392+ slot = createNode(a.height - 1,0);
390393 write++;
391394 }
392395 }
393396
394397 // Cleanup after the loop. Copy the last slot into the new nodes.
395− if (slot._1.length > 0) {
398+ if (slot.table.length > 0) {
396399 saveSlot(newA, newB, write, slot);
397400 write++;
398401 }
399402
400403 // Shift the untouched slots to the left
401− while (read < a._1.length + b._1.length ) {
402− saveSlot(newA, newB, write, get2(a._1, b._1, read));
404+ while (read < a.table.length + b.table.length ) {
405+ saveSlot(newA, newB, write, get2(a.table, b.table, read));
403406 read++; write++;
404407 }
405408
406409 return [newA, newB];
407410 }
408411
409− // Helper functions
410− function botRight(a) { return a._1[a._1.length - 1]; }
411− function botLeft(a) { return a._1[0]; }
412+ // Navigation functions
413+ function botRight(a) { return a.table[a.table.length - 1]; }
414+ function botLeft(a) { return a.table[0]; }
412415
413− // Copies a node for updating. Note that you should not use
414− // this if only updating one of _1 and _2 for performance reasons.
416+ // Copies a node for updating. Note that you should not use this if
417+ // only updating only one of "table" or "lengths" for performance reasons.
415418 function nodeCopy(a) {
416− var newA = { ctor:"_Array", _0:a._0
417− , _1:a._1.slice() };
418− if (a._0 > 0) { newA._2 = a._2.slice(); }
419+ var newA = { ctor:"_Array", height:a.height
420+ , table:a.table.slice() };
421+ if (a.height > 0) { newA.lengths = a.lengths.slice(); }
419422 return newA;
420423 }
421424
422425 // Returns how many items are in the tree.
423426 function length(a) {
424− if (a._0 == 0) {
425− return a._1.length;
427+ if (a.height == 0) {
428+ return a.table.length;
426429 } else {
427− return a._2[a._2.length - 1];
430+ return a.lengths[a.lengths.length - 1];
428431 }
429432 }
430433
431− // Calculates in which slot the item probably is, then
432− // find the exact slot in the size table ._2. Returns the index.
434+ // Calculates in which slot of "table" the item probably is, then
435+ // find the exact slot via forward searching in "lengths". Returns the index.
433436 function getSlot(i, a) {
434− var slot = Math.floor(i / (Math.pow(M, a._0)));
435− while (a._2[slot] <= i) {
437+ var slot = Math.floor(i / (Math.pow(M, a.height)));
438+ while (a.lengths[slot] <= i) {
436439 slot++
437440 }
438441 return slot;
@@ -440,45 +443,45 @@ Elm.Native.Array.make = function(elm) {
440443
441444 // Recursively creates a tree with a given height containing
442445 // only the given item.
443− function create(item, height) {
444− if (height == 0) {
445− return { ctor:"_Array", _0:0
446− , _1:[item] };
446+ function create(item, h) {
447+ if (h == 0) {
448+ return { ctor:"_Array", height:0
449+ , table:[item] };
447450 } else {
448− return { ctor:"_Array", _0:height
449− , _1:[create(item, height - 1)]
450− , _2:[1] };
451+ return { ctor:"_Array", height:h
452+ , table:[create(item, h - 1)]
453+ , lengths:[1] };
451454 }
452455 }
453456
454457 // Recursively creates a tree that contains the given tree.
455− function parentise(tree, height) {
456− if (height == tree._0) {
458+ function parentise(tree, h) {
459+ if (h == tree.height) {
457460 return tree;
458461 } else {
459− return { ctor:"_Array", _0:height
460− , _1:[parentise(tree, height - 1)]
461− , _2:[length(tree)] };
462+ return { ctor:"_Array", height:h
463+ , table:[parentise(tree, h - 1)]
464+ , lengths:[length(tree)] };
462465 }
463466 }
464467
465468 // Emphasizes blood brotherhood beneath two trees.
466469 function siblise(a, b) {
467− return { ctor:"_Array", _0:a._0 + 1
468− , _1:[a, b]
469− , _2:[length(a), length(a) + length(b)] };
470+ return { ctor:"_Array", height:a.height + 1
471+ , table:[a, b]
472+ , lengths:[length(a), length(a) + length(b)] };
470473 }
471474
472475 Elm.Native.Array.values = {
473476 empty:empty,
474− elements:elements,
477+ toList:toList,
475478 concat:F2(concat),
476479 push:F2(push),
477480 slice:F3(slice),
478481 get:F2(get),
479482 set:F3(set),
480483 map:F2(map),
481− assocMap:F2(assocMap),
484+ indexedMap:F2(indexedMap),
482485 foldl:F3(foldl),
483486 foldr:F3(foldr),
484487 length:length
libraries/Native/Show.js+4
@@ -5,6 +5,7 @@ Elm.Native.Show.make = function(elm) {
55 if (elm.Native.Show.values) return elm.Native.Show.values;
66
77 var NList = Elm.Native.List.make(elm);
8+ var Array = Elm.Array.make(elm);
89 var List = Elm.List.make(elm);
910 var Dict = Elm.Dict.make(elm);
1011 var Tuple2 = Elm.Native.Utils.make(elm).Tuple2;
@@ -43,6 +44,9 @@ Elm.Native.Show.make = function(elm) {
4344 output.push(toString(v[k]));
4445 }
4546 return "(" + output.join(",") + ")";
47+ } else if (v.ctor === "_Array") {
48+ var list = Array.toList(v);
49+ return "Array.fromList " + toString(list);
4650 } else if (v.ctor === "::") {
4751 var output = '[' + toString(v._0);
4852 v = v._1;