on master help sign in
Merge pull request #546 from Xashili/array
ad5bdaaEvan Czaplicki
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
8into a list before operating on it, and then turning it back into an array.
8into a list before operating on it, and then turning it back into an array.
9
9
10# Basics
10# Basics
11−@docs empty, length, get, safeGet, getWithDefault
11+@docs empty, length, get, getMaybe, getSafe
12
12
13# Putting Arrays Together
13# Putting Arrays Together
14@docs fill, fromList, concat, set, updates, push
14@docs fill, fromList, concat, set, updates, push
15
15
16# Taking Arrays Apart
16# Taking Arrays Apart
17−@docs elements, indices, assocs, slice
17+@docs toList, toIndexedList, indices, slice
18
18
19# Mapping, folding, zipping
19# Mapping, folding, zipping
20−@docs map, assocMap, foldl, foldr, zip, zipWith
20+@docs map, indexedMap, foldl, foldr, zip, zipWith
21-}
21-}
22
22
23import Native.Array
23import Native.Array
@@ -34,16 +34,17 @@ data Array a = Array
34fill : Int -> a -> Array a
34fill : Int -> a -> Array a
35fill len e = fromList <| List.map (always e) [1..len]
35fill len e = fromList <| List.map (always e) [1..len]
36
36
37+-- TODO: make this a native function.
37{-| Create an array from a list. -}
38{-| Create an array from a list. -}
38fromList : [a] -> Array a
39fromList : [a] -> Array a
39fromList = List.foldl (Native.Array.push) Native.Array.empty
40fromList = List.foldl (Native.Array.push) Native.Array.empty
40
41
41{-| Create a list of elements from an array.
42{-| Create a list of elements from an array.
42
43
43− elements (fromList [3,5,8]) == [3,5,8]
44+ toList (fromList [3,5,8]) == [3,5,8]
44-}
45-}
45−elements : Array a -> [a]
46+toList : Array a -> [a]
46−elements = Native.Array.toList
47+toList = Native.Array.toList
47
48
48{-| Create a list of the possible indices of an array.
49{-| Create a list of the possible indices of an array.
49
50
@@ -52,12 +53,13 @@ elements = Native.Array.toList
52indices : Array a -> [Int]
53indices : Array a -> [Int]
53indices a = [0..Native.Array.length a - 1]
54indices a = [0..Native.Array.length a - 1]
54
55
56+-- TODO: make this a native function.
55{-| Create a list of tuples (Index, Element) from an array.
57{-| Create a list of tuples (Index, Element) from an array.
56
58
57− assocs (fromList [3,5,8]) == [(0,3), (1,5), (2,8)]
59+ toIndexedList (fromList [3,5,8]) == [(0,3), (1,5), (2,8)]
58-}
60-}
59−assocs : Array a -> [(Int, a)]
61+toIndexedList : Array a -> [(Int, a)]
60−assocs a = List.zip (indices a) (Native.Array.elements a)
62+toIndexedList a = List.zip (indices a) (Native.Array.toList a)
61
63
62{-| Apply a function on every element in an array.
64{-| Apply a function on every element in an array.
63
65
@@ -66,12 +68,12 @@ assocs a = List.zip (indices a) (Native.Array.elements a)
66map : (a -> b) -> Array a -> Array b
68map : (a -> b) -> Array a -> Array b
67map = Native.Array.map
69map = Native.Array.map
68
70
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.
70
72
71− assocMap (*) (fromList [5,5,5]) == fromList [0,5,10]
73+ indexedMap (*) (fromList [5,5,5]) == fromList [0,5,10]
72-}
74-}
73−assocMap : (Int -> a -> b) -> Array a -> Array b
75+indexedMap : (Int -> a -> b) -> Array a -> Array b
74−assocMap = Native.Array.assocMap
76+indexedMap = Native.Array.indexedMap
75
77
76{-| Reduce an array from the left.
78{-| Reduce an array from the left.
77
79
@@ -102,7 +104,7 @@ is longer, the extra elements are dropped.
102-}
104-}
103zipWith : (a -> b -> c) -> Array a -> Array b -> Array c
105zipWith : (a -> b -> c) -> Array a -> Array b -> Array c
104zipWith f a b =
106zipWith 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)
106
108
107{-| Return an empty array.
109{-| Return an empty array.
108
110
@@ -126,28 +128,25 @@ array length is unkown, use safeGet oder getWithDefault.
126get : Int -> Array a -> a
128get : Int -> Array a -> a
127get = Native.Array.get
129get = Native.Array.get
128
130
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.
130
132
131− safeGet 2 (A.fromList [3,2,1]) == Just 2
133+ getMaybe 2 (A.fromList [3,2,1]) == Just 2
132− safeGet 5 (A.fromList [3,2,1]) == Nothing
134+ getMaybe 5 (A.fromList [3,2,1]) == Nothing
133-}
135-}
134−safeGet : Int -> Array a -> Maybe a
136+getMaybe : Int -> Array a -> Maybe a
135−safeGet i array =
136− if i < Native.Array.length array
137+getMaybe i array = if Native.Array.length array > i
137− then Just (Native.Array.get i array)
138+ then Just (Native.Array.get i array)
138− else Nothing
139+ else Nothing
139
140
140{-| Get the element at the index. If the index is out of range, the given default
141{-| Get the element at the index. If the index is out of range, the given default
141−elementis returned.
142+element is returned.
142
143
143− getWithDefault 0 2 (A.fromList [3,2,1]) == 1
144+ getSafe 0 2 (A.fromList [3,2,1]) == 1
144− getWithDefault 0 5 (A.fromList [3,2,1]) == 0
145+ getSafe 0 5 (A.fromList [3,2,1]) == 0
145-}
146-}
146−getWithDefault : a -> Int -> Array a -> a
147+getSafe : a -> Int -> Array a -> a
147−getWithDefault default i array =
148− if i < Native.Array.length array
148+getSafe default i array = if Native.Array.length array > i
149− then Native.Array.get i array
149+ then Native.Array.get i array else default
150− else default
151
150
152{-| Set the element at the index. Returns the updated array, or if the index is
151{-| Set the element at the index. Returns the updated array, or if the index is
153out of range, the unaltered array.
152out of range, the unaltered array.
@@ -162,7 +161,7 @@ set = Native.Array.set
162 updates [(1,7),(2,8)] (fill 3 1) == fromList [1,7,8]
161 updates [(1,7),(2,8)] (fill 3 1) == fromList [1,7,8]
163-}
162-}
164updates : [(Int, a)] -> Array a -> Array a
163updates : [(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
166
165
167{-| Slice an array given a range. The selection is inclusive, so the last
166{-| Slice an array given a range. The selection is inclusive, so the last
168element in the selection will also be in the new array. This may change in the
167element 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) {
8
8
9 var List = Elm.Native.List.make(elm);
9 var List = Elm.Native.List.make(elm);
10
10
11− // An RRB-Tree has two distinct data types. A leaf which contains data as
11+ // A RRB-Tree has two distinct data types.
12− // an array in _1, and a height in _0, that is always 0. A node has in
12+ // Leaf -> "height" is always 0
13− // addition its size table in _2, while _1 contains an array of nodes or
13+ // "table" is an array of elements
14− // leaves.
14+ // Node -> "height" is always greater than 0
15−
15+ // "table" is an array of child nodes
16+ // "lengths" is an array of accumulated lengths of the child nodes
17+
16− // M is the maximal node size. 32 seems fast. E is the allowed increase
18+ // M is the maximal table size. 32 seems fast. E is the allowed increase
17 // of search steps when concatting to find an index. Lower values will
19 // of search steps when concatting to find an index. Lower values will
18 // decrease balancing, but will increase search steps.
20 // decrease balancing, but will increase search steps.
19 var M = 32;
21 var M = 32;
20 var E = 2;
22 var E = 2;
21
23
22 // An empty array.
24 // An empty array.
23− var empty = { ctor:"_Array", _0:0, _1:new Array() };
25+ var empty = { ctor:"_Array", height:0, table:new Array() };
24
26
25 // Gets the value at index i recursively.
27 // Gets the value at index i recursively.
26 function get(i, a) {
28 function get(i, a) {
27− if (a._0 == 0) {
29+ if (a.height == 0) {
28− if (i < a._1.length) {
30+ if (i < a.table.length) {
29− return a._1[i];
31+ return a.table[i];
30 } else {
32 } 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.");
32 }
34 }
33 }
35 }
34
36
35 var slot = getSlot(i, a);
37 var slot = getSlot(i, a);
36− var sub = slot > 0 ? a._2[slot-1] : 0;
38+ var sub = slot > 0 ? a.lengths[slot-1] : 0;
37− return get(i - sub, a._1[slot]);
39+ return get(i - sub, a.table[slot]);
38 }
40 }
39
41
40 // Sets the value at the index i. Only the nodes leading to i will get
42 // 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) {
44 return a;
46 return a;
45 }
47 }
46 var newA = nodeCopy(a);
48 var newA = nodeCopy(a);
47− newA._1 = a._1.slice();
49+ newA.table = a.table.slice();
48
50
49− if (a._0 == 0) {
51+ if (a.height == 0) {
50− newA._1[i] = item;
52+ newA.table[i] = item;
51 } else {
53 } else {
52 var slot = getSlot(i, a);
54 var slot = getSlot(i, a);
53− var sub = slot > 0 ? a._2[slot-1] : 0;
55+ var sub = slot > 0 ? a.lengths[slot-1] : 0;
54− newA._1[slot] = set(i - sub, item, a._1[slot]);
56+ newA.table[slot] = set(i - sub, item, a.table[slot]);
55 }
57 }
56 return newA;
58 return newA;
57 }
59 }
@@ -63,7 +65,7 @@ Elm.Native.Array.make = function(elm) {
63 return pushed;
65 return pushed;
64 }
66 }
65
67
66− newTree = create(item, a._0);
68+ newTree = create(item, a.height);
67 return siblise(a, newTree);
69 return siblise(a, newTree);
68 }
70 }
69
71
@@ -72,10 +74,10 @@ Elm.Native.Array.make = function(elm) {
72 // null will be returned.
74 // null will be returned.
73 function push_(item, a) {
75 function push_(item, a) {
74 // Handle resursion stop at leaf level.
76 // Handle resursion stop at leaf level.
75− if (a._0 == 0) {
77+ if (a.height == 0) {
76− if (a._1.length < M) {
78+ if (a.table.length < M) {
77− var newA = { ctor:"_Array", _0:0, _1:a._1.slice() };
79+ var newA = { ctor:"_Array", height:0, table:a.table.slice() };
78− newA._1.push(item);
80+ newA.table.push(item);
79 return newA;
81 return newA;
80 } else {
82 } else {
81 return null;
83 return null;
@@ -89,19 +91,19 @@ Elm.Native.Array.make = function(elm) {
89 // be updated.
91 // be updated.
90 if (pushed != null) {
92 if (pushed != null) {
91 var newA = nodeCopy(a);
93 var newA = nodeCopy(a);
92− newA._1[newA._1.length - 1] = pushed;
94+ newA.table[newA.table.length - 1] = pushed;
93− newA._2[newA._2.length - 1]++;
95+ newA.lengths[newA.lengths.length - 1]++;
94 return newA
96 return newA
95 }
97 }
96
98
97 // When there was no space left, check if there is space left
99 // When there was no space left, check if there is space left
98 // for a new slot with a tree which contains only the item
100 // for a new slot with a tree which contains only the item
99 // at the bottom.
101 // at the bottom.
100− if (a._1.length < M) {
102+ if (a.table.length < M) {
101− var newSlot = create(item, a._0 - 1);
103+ var newSlot = create(item, a.height - 1);
102 var newA = nodeCopy(a);
104 var newA = nodeCopy(a);
103− newA._1.push(newSlot);
105+ newA.table.push(newSlot);
104− newA._2.push(newA._2[newA._2.length - 1] + length(newSlot));
106+ newA.lengths.push(newA.lengths[newA.lengths.length - 1] + length(newSlot));
105 return newA
107 return newA
106 } else {
108 } else {
107 return null;
109 return null;
@@ -109,53 +111,54 @@ Elm.Native.Array.make = function(elm) {
109 }
111 }
110
112
111 // Converts an array into a list of elements.
113 // Converts an array into a list of elements.
112− function elements(a) {
114+ function toList(a) {
113− return elements_(List.Nil, a);
115+ return toList_(List.Nil, a);
114 }
116 }
115
117
116− function elements_(list, a) {
118+ function toList_(list, a) {
117− for (var i = a._1.length - 1; i >= 0; i--) {
119+ for (var i = a.table.length - 1; i >= 0; i--) {
118− list = a._0 == 0 ? List.Cons(a._1[i], list) : elements_(list, a._1[i]);
120+ list = a.height == 0 ? List.Cons(a.table[i], list) : toList_(list, a.table[i]);
119 }
121 }
120 return list;
122 return list;
121 }
123 }
122
124
123− // Maps a function over an array.
125+ // Maps a function over the elements of an array.
124 function map(f, a) {
126 function map(f, a) {
125− var newA = { ctor:"_Array", _0:a._0, _1:new Array(a._1) };
127+ var newA = { ctor:"_Array", height:a.height, table:new Array(a.table) };
126− if (a._0 > 0) { newA._2 = a._2; }
128+ if (a.height > 0) { newA.lengths = a.lengths; }
127− for (var i = 0; i < a._1.length; i++) {
129+ for (var i = 0; i < a.table.length; i++) {
128− newA._1[i] = a._0 == 0 ? f(a._1[i]) : map(f, a._1[i]);
130+ newA.table[i] = a.height == 0 ? f(a.table[i]) : map(f, a.table[i]);
129 }
131 }
130 return newA;
132 return newA;
131 }
133 }
132
134
135+ // Maps a function over the elements with their index as first argument.
133− function assocMap(f, a) {
136+ function indexedMap(f, a) {
134− var newA = { ctor:"_Array", _0:a._0, _1:new Array(a._1) };
137+ var newA = { ctor:"_Array", height:a.height, table:new Array(a.table) };
135− if (a._0 > 0) { newA._2 = a._2; }
138+ if (a.height > 0) { newA.lengths = a.lengths; }
136− for (var i = 0; i < a._1.length; i++) {
139+ for (var i = 0; i < a.table.length; i++) {
137− newA._1[i] = a._0 == 0 ? A2(f, i, a._1[i]) : assocMap(f, a._1[i]);
140+ newA.table[i] = a.height == 0 ? A2(f, i, a.table[i]) : indexedMap(f, a.table[i]);
138 }
141 }
139 return newA;
142 return newA;
140 }
143 }
141
144
142 function foldl(f, b, a) {
145 function foldl(f, b, a) {
143− for (var i = a._1.length - 1; i >= 0; i--) {
146+ for (var i = a.table.length - 1; i >= 0; i--) {
144− b = A2(f, a._0 == 0 ? a._1[i] : foldl(f, b, a._1[i]), b);
147+ b = A2(f, a.height == 0 ? a.table[i] : foldl(f, b, a.table[i]), b);
145 }
148 }
146 return b;
149 return b;
147 }
150 }
148
151
149 function foldr(f, b, a) {
152 function foldr(f, b, a) {
150− for (var i = 0; i < a._1.length; i++) {
153+ for (var i = 0; i < a.table.length; i++) {
151− b = A2(f, a._0 == 0 ? a._1[i] : foldr(f, b, a._1[i]), b);
154+ b = A2(f, a.height == 0 ? a.table[i] : foldr(f, b, a.table[i]), b);
152 }
155 }
153 return b;
156 return b;
154 }
157 }
155
158
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,
157 // when I understand, why e.g. JS does not handle it this way. :-)
160 // 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.
159 // TODO: currently, it slices the right, then the left. This can be
162 // TODO: currently, it slices the right, then the left. This can be
160 // optimized.
163 // optimized.
161 function slice(from, to, a) {
164 function slice(from, to, a) {
@@ -170,15 +173,15 @@ Elm.Native.Array.make = function(elm) {
170 }
173 }
171
174
172 // Handle leaf level.
175 // Handle leaf level.
173− if (a._0 == 0) {
176+ if (a.height == 0) {
174− var newA = { ctor:"_Array", _0:0 };
177+ var newA = { ctor:"_Array", height:0 };
175− newA._1 = a._1.slice(0, to + 1);
178+ newA.table = a.table.slice(0, to + 1);
176 return newA;
179 return newA;
177 }
180 }
178
181
179 // Slice the right recursively.
182 // Slice the right recursively.
180 var right = getSlot(to, a);
183 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]);
182
185
183 // Maybe the a node is not even needed, as sliced contains the whole slice.
186 // Maybe the a node is not even needed, as sliced contains the whole slice.
184 if (right == 0) {
187 if (right == 0) {
@@ -186,11 +189,11 @@ Elm.Native.Array.make = function(elm) {
186 }
189 }
187
190
188 // Create new node.
191 // Create new node.
189− var newA = { ctor:"_Array", _0:a._0
192+ var newA = { ctor:"_Array", height:a.height
190− , _1:a._1.slice(0, right + 1)
193+ , table:a.table.slice(0, right + 1)
191− , _2:a._2.slice(0, right + 1) };
194+ , lengths:a.lengths.slice(0, right + 1) };
192− newA._1[right] = sliced;
195+ newA.table[right] = sliced;
193− newA._2[right] = length(sliced) + (right > 0 ? newA._2[right - 1] : 0);
196+ newA.lengths[right] = length(sliced) + (right > 0 ? newA.lengths[right - 1] : 0);
194 return newA;
197 return newA;
195 }
198 }
196
199
@@ -200,30 +203,30 @@ Elm.Native.Array.make = function(elm) {
200 }
203 }
201
204
202 // Handle leaf level.
205 // Handle leaf level.
203− if (a._0 == 0) {
206+ if (a.height == 0) {
204− var newA = { ctor:"_Array", _0:0 };
207+ var newA = { ctor:"_Array", height:0 };
205− newA._1 = a._1.slice(from, a._1.length + 1);
208+ newA.table = a.table.slice(from, a.table.length + 1);
206 return newA;
209 return newA;
207 }
210 }
208
211
209 // Slice the left recursively.
212 // Slice the left recursively.
210 var left = getSlot(from, a);
213 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]);
212
215
213 // Maybe the a node is not even needed, as sliced contains the whole slice.
216 // 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) {
215 return sliced;
218 return sliced;
216 }
219 }
217
220
218 // Create new node.
221 // Create new node.
219− var newA = { ctor:"_Array", _0:a._0
222+ var newA = { ctor:"_Array", height:a.height
220− , _1:a._1.slice(left, a._1.length + 1)
223+ , table:a.table.slice(left, a.table.length + 1)
221− , _2:new Array(a._1.length - left) };
224+ , lengths:new Array(a.table.length - left) };
222− newA._1[left] = sliced;
225+ newA.table[left] = sliced;
223 var len = 0;
226 var len = 0;
224− for (var i = 0; i < newA._1.length; i++) {
227+ for (var i = 0; i < newA.table.length; i++) {
225− len += length(newA._1[i]);
228+ len += length(newA.table[i]);
226− newA._2[i] = len;
229+ newA.lengths[i] = len;
227 }
230 }
228
231
229 return newA;
232 return newA;
@@ -233,12 +236,12 @@ Elm.Native.Array.make = function(elm) {
233 // TODO: Add support for concatting trees of different sizes. Current
236 // TODO: Add support for concatting trees of different sizes. Current
234 // behavior will just rise the lower tree and then concat them.
237 // behavior will just rise the lower tree and then concat them.
235 function concat(a, b) {
238 function concat(a, b) {
236− if (b._0 > a._0) { return concat(parentise(a, b._0), b); }
239+ if (b.height > a.height) { return concat(parentise(a, b.height), b); }
237− if (a._0 > b._0) { return concat(a, parentise(b, a._0)); }
240+ if (a.height > b.height) { return concat(a, parentise(b, a.height)); }
238− if (a._0 == 0) { return concat(parentise(a, 1), parentise(b, 1)); }
241+ if (a.height == 0) { return concat(parentise(a, 1), parentise(b, 1)); }
239
242
240 var c = concat_(a, b);
243 var c = concat_(a, b);
241− if (c[1]._1.length > 0) {
244+ if (c[1].table.length > 0) {
242 return siblise(c[0], c[1]);
245 return siblise(c[0], c[1]);
243 } else {
246 } else {
244 return c[0];
247 return c[0];
@@ -249,7 +252,7 @@ Elm.Native.Array.make = function(elm) {
249 // needs to be handled by the function, that called concat_. May be only
252 // needs to be handled by the function, that called concat_. May be only
250 // called for trees with an minimal height of 1.
253 // called for trees with an minimal height of 1.
251 function concat_(a, b) {
254 function concat_(a, b) {
252− if (a._0 == 1) {
255+ if (a.height == 1) {
253 // Check if balancing is needed and return based on that.
256 // Check if balancing is needed and return based on that.
254 var toRemove = calcToRemove(a, b);
257 var toRemove = calcToRemove(a, b);
255 if (toRemove <= E) {
258 if (toRemove <= E) {
@@ -263,29 +266,29 @@ Elm.Native.Array.make = function(elm) {
263 a = nodeCopy(a), b = nodeCopy(b);
266 a = nodeCopy(a), b = nodeCopy(b);
264
267
265 // Adjust the bottom right side of the new tree.
268 // Adjust the bottom right side of the new tree.
266− a._1[a._1.length - 1] = concated[0];
269+ a.table[a.table.length - 1] = concated[0];
267− a._2[a._2.length - 1] = length(concated[0])
270+ a.lengths[a.lengths.length - 1] = length(concated[0])
268− a._2[a._2.length - 1] += a._2.length > 1 ? a._2[a._2.length - 2] : 0;
271+ a.lengths[a.lengths.length - 1] += a.lengths.length > 1 ? a.lengths[a.lengths.length - 2] : 0;
269
272
270 // Adjust the bottom left side of the new tree.
273 // Adjust the bottom left side of the new tree.
271− if (concated[1]._1.length > 0) {
274+ if (concated[1].table.length > 0) {
272− b._1[0] = concated[1];
275+ b.table[0] = concated[1];
273− b._2[0] = length(concated[1]);
276+ b.lengths[0] = length(concated[1]);
274− for (var i = 1, len = length(b._1[0]); i < b._2.length; i++) {
277+ for (var i = 1, len = length(b.table[0]); i < b.lengths.length; i++) {
275− len += length(b._1[i]);
278+ len += length(b.table[i]);
276− b._2[i] = len;
279+ b.lengths[i] = len;
277 }
280 }
278 } else {
281 } else {
279− b._1.shift();
282+ b.table.shift();
280− for (var i = 1; i < b._2.length; i++) {
283+ for (var i = 1; i < b.lengths.length; i++) {
281− b._2[i] = b._2[i] - b._2[0];
284+ b.lengths[i] = b.lengths[i] - b.lengths[0];
282 }
285 }
283− b._2.shift();
286+ b.lengths.shift();
284 }
287 }
285
288
286 // Check if balancing is needed and return based on that.
289 // Check if balancing is needed and return based on that.
287 var toRemove = calcToRemove(a, b);
290 var toRemove = calcToRemove(a, b);
288− if (toRemove <= E || b._1.length == 0) {
291+ if (toRemove <= E || b.table.length == 0) {
289 return [a,b];
292 return [a,b];
290 }
293 }
291
294
@@ -295,18 +298,18 @@ Elm.Native.Array.make = function(elm) {
295 // Returns the extra search steps for E. Refer to the paper.
298 // Returns the extra search steps for E. Refer to the paper.
296 function calcToRemove(a, b) {
299 function calcToRemove(a, b) {
297 var subLengths = 0;
300 var subLengths = 0;
298− for (var i = 0; i < a._1.length; i++) {
301+ for (var i = 0; i < a.table.length; i++) {
299− subLengths += a._1[i]._1.length;
302+ subLengths += a.table[i].table.length;
300 }
303 }
301− for (var i = 0; i < b._1.length; i++) {
304+ for (var i = 0; i < b.table.length; i++) {
302− subLengths += b._1[i]._1.length;
305+ subLengths += b.table[i].table.length;
303 }
306 }
304
307
305− var toRemove = a._1.length + b._1.length
308+ var toRemove = a.table.length + b.table.length
306 return toRemove - (Math.floor((subLengths - 1) / M) + 1);
309 return toRemove - (Math.floor((subLengths - 1) / M) + 1);
307 }
310 }
308
311
309− // get2 and set2 are helpers for accessing over two arrays.
312+ // get2, set2 and saveSlot are helpers for accessing elements over two arrays.
310 function get2(a, b, index) {
313 function get2(a, b, index) {
311 return index < a.length ? a[index] : b[index - a.length];
314 return index < a.length ? a[index] : b[index - a.length];
312 }
315 }
@@ -319,59 +322,59 @@ Elm.Native.Array.make = function(elm) {
319 }
322 }
320 }
323 }
321
324
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+
322 // Creates a node or leaf with a given length at their arrays for perfomance.
333 // Creates a node or leaf with a given length at their arrays for perfomance.
323 // Is only used by shuffle.
334 // Is only used by shuffle.
324− function createNode(height, length) {
335+ function createNode(h, length) {
325 if (length < 0) { length = 0; }
336 if (length < 0) { length = 0; }
326− var a = { ctor:"_Array", _0:height, _1:new Array(length) };
337+ var a = { ctor:"_Array", height:h, table:new Array(length) };
327− if (height > 0) {
338+ if (h > 0) {
328− a._2 = new Array(length);
339+ a.lengths = new Array(length);
329 }
340 }
330 return a;
341 return a;
331 }
342 }
332
343
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−
341 // Returns an array of two balanced nodes.
344 // Returns an array of two balanced nodes.
342 function shuffle(a, b, toRemove) {
345 function shuffle(a, b, toRemove) {
343− var newA = createNode(a._0, Math.min(M, a._1.length + b._1.length - toRemove));
346+ var newA = createNode(a.height, Math.min(M, a.table.length + b.table.length - toRemove));
344− var newB = createNode(a._0, newA._1.length - (a._1.length + b._1.length - toRemove));
347+ var newB = createNode(a.height, newA.table.length - (a.table.length + b.table.length - toRemove));
345
348
346 // Skip the slots with size M. More precise: copy the slot references
349 // Skip the slots with size M. More precise: copy the slot references
347 // to the new node
350 // to the new node
348 var read = 0;
351 var read = 0;
349− while (get2(a._1, b._1, read)._1.length % M == 0) {
352+ while (get2(a.table, b.table, read).table.length % M == 0) {
350− set2(newA._1, newB._1, read, get2(a._1, b._1, read));
353+ set2(newA.table, newB.table, read, get2(a.table, b.table, read));
351− set2(newA._2, newB._2, read, get2(a._2, b._2, read));
354+ set2(newA.lengths, newB.lengths, read, get2(a.lengths, b.lengths, read));
352 read++;
355 read++;
353 }
356 }
354
357
355 // Pulling items from left to right, caching in a slot before writing
358 // Pulling items from left to right, caching in a slot before writing
356 // it into the new nodes.
359 // it into the new nodes.
357 var write = read;
360 var write = read;
358− var slot = new createNode(a._0 - 1, 0);
361+ var slot = new createNode(a.height - 1, 0);
359 var from = 0;
362 var from = 0;
360
363
361 // If the current slot is still containing data, then there will be at
364 // If the current slot is still containing data, then there will be at
362 // least one more write, so we do not break this loop yet.
365 // 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) {
364 // Find out the max possible items for copying.
367 // Find out the max possible items for copying.
365− var source = get2(a._1, b._1, read);
368+ var source = get2(a.table, b.table, read);
366− var to = Math.min(M - slot._1.length, source._1.length)
369+ var to = Math.min(M - slot.table.length, source.table.length)
367
370
368 // Copy and adjust size table.
371 // Copy and adjust size table.
369− slot._1 = slot._1.concat(source._1.slice(from, to));
372+ slot.table = slot.table.concat(source.table.slice(from, to));
370− if (slot._0 > 0) {
373+ if (slot.height > 0) {
371− var len = slot._2.length;
374+ var len = slot.lengths.length;
372 for (var i = len; i < len + to - from; i++) {
375 for (var i = len; i < len + to - from; i++) {
373− slot._2[i] = length(slot._1[i]);
376+ slot.lengths[i] = length(slot.table[i]);
374− slot._2[i] += (i > 0 ? slot._2[i - 1] : 0);
377+ slot.lengths[i] += (i > 0 ? slot.lengths[i - 1] : 0);
375 }
378 }
376 }
379 }
377
380
@@ -379,60 +382,60 @@ Elm.Native.Array.make = function(elm) {
379
382
380 // Only proceed to next slots[i] if the current one was
383 // Only proceed to next slots[i] if the current one was
381 // fully copied.
384 // fully copied.
382− if (source._1.length <= to) {
385+ if (source.table.length <= to) {
383 read++; from = 0;
386 read++; from = 0;
384 }
387 }
385
388
386 // Only create a new slot if the current one is filled up.
389 // Only create a new slot if the current one is filled up.
387− if (slot._1.length == M) {
390+ if (slot.table.length == M) {
388 saveSlot(newA, newB, write, slot);
391 saveSlot(newA, newB, write, slot);
389− slot = createNode(a._0 - 1,0);
392+ slot = createNode(a.height - 1,0);
390 write++;
393 write++;
391 }
394 }
392 }
395 }
393
396
394 // Cleanup after the loop. Copy the last slot into the new nodes.
397 // Cleanup after the loop. Copy the last slot into the new nodes.
395− if (slot._1.length > 0) {
398+ if (slot.table.length > 0) {
396 saveSlot(newA, newB, write, slot);
399 saveSlot(newA, newB, write, slot);
397 write++;
400 write++;
398 }
401 }
399
402
400 // Shift the untouched slots to the left
403 // Shift the untouched slots to the left
401− while (read < a._1.length + b._1.length ) {
404+ while (read < a.table.length + b.table.length ) {
402− saveSlot(newA, newB, write, get2(a._1, b._1, read));
405+ saveSlot(newA, newB, write, get2(a.table, b.table, read));
403 read++; write++;
406 read++; write++;
404 }
407 }
405
408
406 return [newA, newB];
409 return [newA, newB];
407 }
410 }
408
411
409− // Helper functions
412+ // Navigation functions
410− function botRight(a) { return a._1[a._1.length - 1]; }
413+ function botRight(a) { return a.table[a.table.length - 1]; }
411− function botLeft(a) { return a._1[0]; }
414+ function botLeft(a) { return a.table[0]; }
412
415
413− // Copies a node for updating. Note that you should not use
416+ // Copies a node for updating. Note that you should not use this if
414− // this if only updating one of _1 and _2 for performance reasons.
417+ // only updating only one of "table" or "lengths" for performance reasons.
415 function nodeCopy(a) {
418 function nodeCopy(a) {
416− var newA = { ctor:"_Array", _0:a._0
419+ var newA = { ctor:"_Array", height:a.height
417− , _1:a._1.slice() };
420+ , table:a.table.slice() };
418− if (a._0 > 0) { newA._2 = a._2.slice(); }
421+ if (a.height > 0) { newA.lengths = a.lengths.slice(); }
419 return newA;
422 return newA;
420 }
423 }
421
424
422 // Returns how many items are in the tree.
425 // Returns how many items are in the tree.
423 function length(a) {
426 function length(a) {
424− if (a._0 == 0) {
427+ if (a.height == 0) {
425− return a._1.length;
428+ return a.table.length;
426 } else {
429 } else {
427− return a._2[a._2.length - 1];
430+ return a.lengths[a.lengths.length - 1];
428 }
431 }
429 }
432 }
430
433
431− // Calculates in which slot the item probably is, then
434+ // Calculates in which slot of "table" the item probably is, then
432− // find the exact slot in the size table ._2. Returns the index.
435+ // find the exact slot via forward searching in "lengths". Returns the index.
433 function getSlot(i, a) {
436 function getSlot(i, a) {
434− var slot = Math.floor(i / (Math.pow(M, a._0)));
437+ var slot = Math.floor(i / (Math.pow(M, a.height)));
435− while (a._2[slot] <= i) {
438+ while (a.lengths[slot] <= i) {
436 slot++
439 slot++
437 }
440 }
438 return slot;
441 return slot;
@@ -440,45 +443,45 @@ Elm.Native.Array.make = function(elm) {
440
443
441 // Recursively creates a tree with a given height containing
444 // Recursively creates a tree with a given height containing
442 // only the given item.
445 // only the given item.
443− function create(item, height) {
446+ function create(item, h) {
444− if (height == 0) {
447+ if (h == 0) {
445− return { ctor:"_Array", _0:0
448+ return { ctor:"_Array", height:0
446− , _1:[item] };
449+ , table:[item] };
447 } else {
450 } else {
448− return { ctor:"_Array", _0:height
451+ return { ctor:"_Array", height:h
449− , _1:[create(item, height - 1)]
452+ , table:[create(item, h - 1)]
450− , _2:[1] };
453+ , lengths:[1] };
451 }
454 }
452 }
455 }
453
456
454 // Recursively creates a tree that contains the given tree.
457 // Recursively creates a tree that contains the given tree.
455− function parentise(tree, height) {
458+ function parentise(tree, h) {
456− if (height == tree._0) {
459+ if (h == tree.height) {
457 return tree;
460 return tree;
458 } else {
461 } else {
459− return { ctor:"_Array", _0:height
462+ return { ctor:"_Array", height:h
460− , _1:[parentise(tree, height - 1)]
463+ , table:[parentise(tree, h - 1)]
461− , _2:[length(tree)] };
464+ , lengths:[length(tree)] };
462 }
465 }
463 }
466 }
464
467
465 // Emphasizes blood brotherhood beneath two trees.
468 // Emphasizes blood brotherhood beneath two trees.
466 function siblise(a, b) {
469 function siblise(a, b) {
467− return { ctor:"_Array", _0:a._0 + 1
470+ return { ctor:"_Array", height:a.height + 1
468− , _1:[a, b]
471+ , table:[a, b]
469− , _2:[length(a), length(a) + length(b)] };
472+ , lengths:[length(a), length(a) + length(b)] };
470 }
473 }
471
474
472 Elm.Native.Array.values = {
475 Elm.Native.Array.values = {
473 empty:empty,
476 empty:empty,
474− elements:elements,
477+ toList:toList,
475 concat:F2(concat),
478 concat:F2(concat),
476 push:F2(push),
479 push:F2(push),
477 slice:F3(slice),
480 slice:F3(slice),
478 get:F2(get),
481 get:F2(get),
479 set:F3(set),
482 set:F3(set),
480 map:F2(map),
483 map:F2(map),
481− assocMap:F2(assocMap),
484+ indexedMap:F2(indexedMap),
482 foldl:F3(foldl),
485 foldl:F3(foldl),
483 foldr:F3(foldr),
486 foldr:F3(foldr),
484 length:length
487 length:length
libraries/Native/Show.js+4
@@ -5,6 +5,7 @@ Elm.Native.Show.make = function(elm) {
5 if (elm.Native.Show.values) return elm.Native.Show.values;
5 if (elm.Native.Show.values) return elm.Native.Show.values;
6
6
7 var NList = Elm.Native.List.make(elm);
7 var NList = Elm.Native.List.make(elm);
8+ var Array = Elm.Array.make(elm);
8 var List = Elm.List.make(elm);
9 var List = Elm.List.make(elm);
9 var Dict = Elm.Dict.make(elm);
10 var Dict = Elm.Dict.make(elm);
10 var Tuple2 = Elm.Native.Utils.make(elm).Tuple2;
11 var Tuple2 = Elm.Native.Utils.make(elm).Tuple2;
@@ -43,6 +44,9 @@ Elm.Native.Show.make = function(elm) {
43 output.push(toString(v[k]));
44 output.push(toString(v[k]));
44 }
45 }
45 return "(" + output.join(",") + ")";
46 return "(" + output.join(",") + ")";
47+ } else if (v.ctor === "_Array") {
48+ var list = Array.toList(v);
49+ return "Array.fromList " + toString(list);
46 } else if (v.ctor === "::") {
50 } else if (v.ctor === "::") {
47 var output = '[' + toString(v._0);
51 var output = '[' + toString(v._0);
48 v = v._1;
52 v = v._1;