@grain/stdlib 0.4.4 → 0.4.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/map.gr CHANGED
@@ -11,21 +11,18 @@ import { allocateArray } from "runtime/dataStructures"
11
11
  record Bucket<k, v> {
12
12
  mut key: k,
13
13
  mut value: v,
14
- mut next: Option<Bucket<k, v>>
14
+ mut next: Option<Bucket<k, v>>,
15
15
  }
16
16
 
17
17
  record Map<k, v> {
18
18
  mut size: Number,
19
- mut buckets: Array<Option<Bucket<k, v>>>
19
+ mut buckets: Array<Option<Bucket<k, v>>>,
20
20
  }
21
21
 
22
22
  // TODO: This could take an `eq` function to custom comparisons
23
- export let makeSized = (size) => {
24
- let buckets = Array.make(size, None);
25
- {
26
- size: 0,
27
- buckets
28
- }
23
+ export let makeSized = size => {
24
+ let buckets = Array.make(size, None)
25
+ { size: 0, buckets }
29
26
  }
30
27
 
31
28
  export let make = () => {
@@ -33,8 +30,8 @@ export let make = () => {
33
30
  }
34
31
 
35
32
  let getBucketIndex = (key, buckets) => {
36
- let bucketsLength = Array.length(buckets);
37
- let hashedKey = hash(key);
33
+ let bucketsLength = Array.length(buckets)
34
+ let hashedKey = hash(key)
38
35
  hashedKey % bucketsLength
39
36
  }
40
37
 
@@ -42,45 +39,45 @@ let rec copyNodeWithNewHash = (oldNode, next, tail) => {
42
39
  match (oldNode) {
43
40
  None => void,
44
41
  Some(node) => {
45
- let idx = getBucketIndex(node.key, next);
46
- let newNode = Some(node);
42
+ let idx = getBucketIndex(node.key, next)
43
+ let newNode = Some(node)
47
44
  match (tail[idx]) {
48
45
  None => {
49
- next[idx] = newNode;
46
+ next[idx] = newNode
50
47
  },
51
48
  Some(tailNode) => {
52
49
  // If there's already a tail node, we add this to the end
53
- tailNode.next = newNode;
54
- }
50
+ tailNode.next = newNode
51
+ },
55
52
  }
56
53
  // Always place this node as the new tail
57
- tail[idx] = newNode;
54
+ tail[idx] = newNode
58
55
  // Recurse with the next node
59
- copyNodeWithNewHash(node.next, next, tail);
60
- }
56
+ copyNodeWithNewHash(node.next, next, tail)
57
+ },
61
58
  }
62
59
  }
63
60
 
64
- let resize = (map) => {
65
- let currentBuckets = map.buckets;
66
- let currentSize = Array.length(currentBuckets);
67
- let nextSize = currentSize * 2;
61
+ let resize = map => {
62
+ let currentBuckets = map.buckets
63
+ let currentSize = Array.length(currentBuckets)
64
+ let nextSize = currentSize * 2
68
65
  if (nextSize >= currentSize) {
69
- let nextBuckets = Array.make(nextSize, None);
66
+ let nextBuckets = Array.make(nextSize, None)
70
67
  // This tracks the tail nodes so we can set their `next` to None
71
- let tailNodes = Array.make(nextSize, None);
72
- map.buckets = nextBuckets;
73
- Array.forEach((old) => {
74
- copyNodeWithNewHash(old, nextBuckets, tailNodes);
75
- }, currentBuckets);
76
- Array.forEach((tail) => {
68
+ let tailNodes = Array.make(nextSize, None)
69
+ map.buckets = nextBuckets
70
+ Array.forEach(old => {
71
+ copyNodeWithNewHash(old, nextBuckets, tailNodes)
72
+ }, currentBuckets)
73
+ Array.forEach(tail => {
77
74
  match (tail) {
78
75
  None => void,
79
76
  Some(node) => {
80
- node.next = None;
81
- }
77
+ node.next = None
78
+ },
82
79
  }
83
- }, tailNodes);
80
+ }, tailNodes)
84
81
  } else {
85
82
  void
86
83
  }
@@ -88,35 +85,35 @@ let resize = (map) => {
88
85
 
89
86
  let rec replaceInBucket = (key, value, node) => {
90
87
  if (key == node.key) {
91
- node.value = value;
88
+ node.value = value
92
89
  false
93
90
  } else {
94
91
  match (node.next) {
95
92
  None => true,
96
- Some(next) => replaceInBucket(key, value, next)
93
+ Some(next) => replaceInBucket(key, value, next),
97
94
  }
98
95
  }
99
96
  }
100
97
 
101
98
  export let set = (key, value, map) => {
102
- let buckets = map.buckets;
99
+ let buckets = map.buckets
103
100
  let idx = getBucketIndex(key, buckets)
104
- let bucket = buckets[idx];
101
+ let bucket = buckets[idx]
105
102
  match (bucket) {
106
103
  None => {
107
- buckets[idx] = Some({ key, value, next: None });
108
- map.size = incr(map.size);
104
+ buckets[idx] = Some({ key, value, next: None })
105
+ map.size = incr(map.size)
109
106
  },
110
107
  Some(node) => {
111
108
  if (replaceInBucket(key, value, node)) {
112
- buckets[idx] = Some({ key, value, next: bucket });
113
- map.size = incr(map.size);
114
- };
115
- }
109
+ buckets[idx] = Some({ key, value, next: bucket })
110
+ map.size = incr(map.size)
111
+ }
112
+ },
116
113
  }
117
114
  // Resize if there are more than 2x the amount of nodes as buckets
118
- if (map.size > (Array.length(buckets) * 2)) {
119
- resize(map);
115
+ if (map.size > Array.length(buckets) * 2) {
116
+ resize(map)
120
117
  } else {
121
118
  void
122
119
  }
@@ -128,18 +125,18 @@ let rec valueFromBucket = (key, node) => {
128
125
  } else {
129
126
  match (node.next) {
130
127
  None => None,
131
- Some(next) => valueFromBucket(key, next)
128
+ Some(next) => valueFromBucket(key, next),
132
129
  }
133
130
  }
134
131
  }
135
132
 
136
133
  export let get = (key, map) => {
137
- let buckets = map.buckets;
138
- let idx = getBucketIndex(key, buckets);
139
- let bucket = buckets[idx];
134
+ let buckets = map.buckets
135
+ let idx = getBucketIndex(key, buckets)
136
+ let bucket = buckets[idx]
140
137
  match (bucket) {
141
138
  None => None,
142
- Some(node) => valueFromBucket(key, node)
139
+ Some(node) => valueFromBucket(key, node),
143
140
  }
144
141
  }
145
142
 
@@ -149,18 +146,18 @@ let rec nodeInBucket = (key, node) => {
149
146
  } else {
150
147
  match (node.next) {
151
148
  None => false,
152
- Some(next) => nodeInBucket(key, next)
149
+ Some(next) => nodeInBucket(key, next),
153
150
  }
154
151
  }
155
152
  }
156
153
 
157
154
  export let contains = (key, map) => {
158
- let buckets = map.buckets;
159
- let idx = getBucketIndex(key, buckets);
160
- let bucket = buckets[idx];
155
+ let buckets = map.buckets
156
+ let idx = getBucketIndex(key, buckets)
157
+ let bucket = buckets[idx]
161
158
  match (bucket) {
162
159
  None => false,
163
- Some(node) => nodeInBucket(key, node)
160
+ Some(node) => nodeInBucket(key, node),
164
161
  }
165
162
  }
166
163
 
@@ -169,115 +166,115 @@ let rec removeInBucket = (key, node) => {
169
166
  None => false,
170
167
  Some(next) => {
171
168
  if (key == next.key) {
172
- node.next = next.next;
169
+ node.next = next.next
173
170
  true
174
171
  } else {
175
172
  removeInBucket(key, next)
176
173
  }
177
- }
174
+ },
178
175
  }
179
176
  }
180
177
 
181
178
  export let remove = (key, map) => {
182
- let buckets = map.buckets;
183
- let idx = getBucketIndex(key, buckets);
184
- let bucket = buckets[idx];
179
+ let buckets = map.buckets
180
+ let idx = getBucketIndex(key, buckets)
181
+ let bucket = buckets[idx]
185
182
  match (bucket) {
186
183
  None => void,
187
184
  Some(node) => {
188
185
  // If it is a top-level node, just replace with next node
189
186
  if (key == node.key) {
190
- map.size = decr(map.size);
191
- buckets[idx] = node.next;
187
+ map.size = decr(map.size)
188
+ buckets[idx] = node.next
192
189
  } else {
193
190
  if (removeInBucket(key, node)) {
194
- map.size = decr(map.size);
191
+ map.size = decr(map.size)
195
192
  }
196
193
  }
197
- }
194
+ },
198
195
  }
199
196
  }
200
197
 
201
198
  export let update = (key, fn, map) => {
202
- let val = get(key, map);
199
+ let val = get(key, map)
203
200
  match (fn(val)) {
204
201
  Some(next) => set(key, next, map),
205
- None => remove(key, map)
202
+ None => remove(key, map),
206
203
  }
207
204
  }
208
205
 
209
- export let size = (map) => {
206
+ export let size = map => {
210
207
  map.size
211
208
  }
212
209
 
213
- export let isEmpty = (map) => {
210
+ export let isEmpty = map => {
214
211
  size(map) == 0
215
212
  }
216
213
 
217
- export let clear = (map) => {
218
- map.size = 0;
219
- let buckets = map.buckets;
214
+ export let clear = map => {
215
+ map.size = 0
216
+ let buckets = map.buckets
220
217
  Array.forEachi((bucket, idx) => {
221
- buckets[idx] = None;
222
- }, buckets);
218
+ buckets[idx] = None
219
+ }, buckets)
223
220
  }
224
221
 
225
222
  let rec forEachBucket = (fn, node) => {
226
223
  match (node) {
227
224
  None => void,
228
225
  Some({ key, value, next }) => {
229
- fn(key, value);
230
- forEachBucket(fn, next);
231
- }
226
+ fn(key, value)
227
+ forEachBucket(fn, next)
228
+ },
232
229
  }
233
230
  }
234
231
 
235
232
  export let forEach = (fn, map) => {
236
- let buckets = map.buckets;
237
- Array.forEach((bucket) => {
233
+ let buckets = map.buckets
234
+ Array.forEach(bucket => {
238
235
  forEachBucket(fn, bucket)
239
- }, buckets);
236
+ }, buckets)
240
237
  }
241
238
 
242
239
  let rec reduceEachBucket = (fn, node, acc) => {
243
240
  match (node) {
244
241
  None => acc,
245
242
  Some({ key, value, next }) =>
246
- reduceEachBucket(fn, next, fn(acc, key, value))
243
+ reduceEachBucket(fn, next, fn(acc, key, value)),
247
244
  }
248
245
  }
249
246
 
250
247
  export let reduce = (fn, init, map) => {
251
- let buckets = map.buckets;
252
- let mut acc = init;
253
- Array.forEach((bucket) => {
248
+ let buckets = map.buckets
249
+ let mut acc = init
250
+ Array.forEach(bucket => {
254
251
  acc = reduceEachBucket(fn, bucket, acc)
255
- }, buckets);
252
+ }, buckets)
256
253
  acc
257
254
  }
258
255
 
259
- export let keys = (map) => {
256
+ export let keys = map => {
260
257
  reduce((list, key, _value) => [key, ...list], [], map)
261
258
  }
262
259
 
263
- export let values = (map) => {
260
+ export let values = map => {
264
261
  reduce((list, _key, value) => [value, ...list], [], map)
265
262
  }
266
263
 
267
- export let toList = (map) => {
264
+ export let toList = map => {
268
265
  reduce((list, key, value) => [(key, value), ...list], [], map)
269
266
  }
270
267
 
271
- export let fromList = (list) => {
272
- let map = make();
273
- List.forEach((pair) => {
274
- let (key, value) = pair;
275
- set(key, value, map);
276
- }, list);
268
+ export let fromList = list => {
269
+ let map = make()
270
+ List.forEach(pair => {
271
+ let (key, value) = pair
272
+ set(key, value, map)
273
+ }, list)
277
274
  map
278
275
  }
279
276
 
280
- let setInArray = (array) => {
277
+ let setInArray = array => {
281
278
  @disableGC
282
279
  let rec iter = (i, key, value) => {
283
280
  array[i] = (key, value)
@@ -289,7 +286,7 @@ let setInArray = (array) => {
289
286
  }
290
287
 
291
288
  @disableGC
292
- export let rec toArray = (map) => {
289
+ export let rec toArray = map => {
293
290
  let length = WasmI32.shrS(WasmI32.fromGrain(map.size), 1n)
294
291
  // TODO(#783): Removing parens around Array<a> causes a parse error
295
292
  let array = WasmI32.toGrain(allocateArray(length)): (Array<a>)
@@ -306,25 +303,24 @@ export let rec toArray = (map) => {
306
303
  array
307
304
  }
308
305
 
309
- export let fromArray = (array) => {
310
- let map = make();
311
- Array.forEach((pair) => {
312
- let (key, value) = pair;
313
- set(key, value, map);
314
- }, array);
306
+ export let fromArray = array => {
307
+ let map = make()
308
+ Array.forEach(pair => {
309
+ let (key, value) = pair
310
+ set(key, value, map)
311
+ }, array)
315
312
  map
316
313
  }
317
314
 
318
315
  export let filter = (predicate, map) => {
319
- let keysToRemove = reduce((list, key, value) =>
320
- if (!predicate(key, value)) {
321
- [key, ...list]
322
- } else {
323
- list
324
- }, [], map);
325
- List.forEach((key) => {
326
- remove(key, map);
327
- }, keysToRemove);
316
+ let keysToRemove = reduce((list, key, value) => if (!predicate(key, value)) {
317
+ [key, ...list]
318
+ } else {
319
+ list
320
+ }, [], map)
321
+ List.forEach(key => {
322
+ remove(key, map)
323
+ }, keysToRemove)
328
324
  }
329
325
 
330
326
  export let reject = (predicate, map) => {
@@ -333,6 +329,6 @@ export let reject = (predicate, map) => {
333
329
 
334
330
  // TODO: Should return a Record type instead of a Tuple
335
331
  // Waiting on https://github.com/grain-lang/grain/issues/190
336
- export let getInternalStats = (map) => {
332
+ export let getInternalStats = map => {
337
333
  (map.size, Array.length(map.buckets))
338
334
  }
package/number.gr CHANGED
@@ -13,7 +13,7 @@ import {
13
13
  coerceNumberToWasmF64,
14
14
  reducedInteger,
15
15
  isFloat,
16
- isBoxedNumber
16
+ isBoxedNumber,
17
17
  } from "runtime/numbers"
18
18
  import { parseInt } from "runtime/stringUtils"
19
19
  import { newFloat64, newInt64 } from "runtime/dataStructures"
@@ -77,15 +77,33 @@ export let rec sqrt = (x: Number) => {
77
77
  let x = WasmI32.fromGrain(x)
78
78
  let sqrtd = WasmF64.sqrt(xval)
79
79
  let ret = if (!isFloat(x) && WasmF64.eq(sqrtd, WasmF64.trunc(sqrtd))) {
80
- WasmI32.toGrain(reducedInteger(WasmI64.truncF64S(sqrtd))): (Number)
80
+ WasmI32.toGrain(reducedInteger(WasmI64.truncF64S(sqrtd))): Number
81
81
  } else {
82
- WasmI32.toGrain(newFloat64(sqrtd)): (Number)
82
+ WasmI32.toGrain(newFloat64(sqrtd)): Number
83
83
  }
84
84
  Memory.decRef(WasmI32.fromGrain(x))
85
85
  Memory.decRef(WasmI32.fromGrain(sqrt))
86
86
  ret
87
87
  }
88
88
 
89
+ /**
90
+ * Determine the positivity or negativity of a Number.
91
+ *
92
+ * @param x: The number to inspect
93
+ * @returns `-1` if the number is negative, `1` if positive, or `0` otherwise; signedness of `-0.0` is preserved
94
+ *
95
+ * @example Number.sign(-10000) == -1
96
+ * @example Number.sign(222222) == 1
97
+ * @example Number.sign(0) == 0
98
+ */
99
+ export let sign = x => {
100
+ match (x) {
101
+ x when x < 0 => -1,
102
+ x when x > 0 => 1,
103
+ _ => 0 * x,
104
+ }
105
+ }
106
+
89
107
  /**
90
108
  * Returns the smaller of its operands.
91
109
  *
@@ -120,7 +138,7 @@ export let max = (x: Number, y: Number) => if (x > y) x else y
120
138
  export let rec ceil = (x: Number) => {
121
139
  let xval = coerceNumberToWasmF64(x)
122
140
  let ceiling = WasmI64.truncF64S(WasmF64.ceil(xval))
123
- let ret = WasmI32.toGrain(reducedInteger(ceiling)): (Number)
141
+ let ret = WasmI32.toGrain(reducedInteger(ceiling)): Number
124
142
  Memory.decRef(WasmI32.fromGrain(x))
125
143
  Memory.decRef(WasmI32.fromGrain(ceil))
126
144
  ret
@@ -138,7 +156,7 @@ export let rec ceil = (x: Number) => {
138
156
  export let rec floor = (x: Number) => {
139
157
  let xval = coerceNumberToWasmF64(x)
140
158
  let floored = WasmI64.truncF64S(WasmF64.floor(xval))
141
- let ret = WasmI32.toGrain(reducedInteger(floored)): (Number)
159
+ let ret = WasmI32.toGrain(reducedInteger(floored)): Number
142
160
  Memory.decRef(WasmI32.fromGrain(x))
143
161
  Memory.decRef(WasmI32.fromGrain(floor))
144
162
  ret
@@ -156,7 +174,7 @@ export let rec floor = (x: Number) => {
156
174
  export let rec trunc = (x: Number) => {
157
175
  let xval = coerceNumberToWasmF64(x)
158
176
  let trunced = WasmI64.truncF64S(xval)
159
- let ret = WasmI32.toGrain(reducedInteger(trunced)): (Number)
177
+ let ret = WasmI32.toGrain(reducedInteger(trunced)): Number
160
178
  Memory.decRef(WasmI32.fromGrain(x))
161
179
  Memory.decRef(WasmI32.fromGrain(trunc))
162
180
  ret
@@ -174,7 +192,7 @@ export let rec trunc = (x: Number) => {
174
192
  export let rec round = (x: Number) => {
175
193
  let xval = coerceNumberToWasmF64(x)
176
194
  let rounded = WasmI64.truncF64S(WasmF64.nearest(xval))
177
- let ret = WasmI32.toGrain(reducedInteger(rounded)): (Number)
195
+ let ret = WasmI32.toGrain(reducedInteger(rounded)): Number
178
196
  Memory.decRef(WasmI32.fromGrain(x))
179
197
  Memory.decRef(WasmI32.fromGrain(round))
180
198
  ret
package/number.md CHANGED
@@ -142,6 +142,40 @@ Returns:
142
142
  |----|-----------|
143
143
  |`Number`|The square root of the operand|
144
144
 
145
+ ### Number.**sign**
146
+
147
+ ```grain
148
+ sign : Number -> Number
149
+ ```
150
+
151
+ Determine the positivity or negativity of a Number.
152
+
153
+ Parameters:
154
+
155
+ |param|type|description|
156
+ |-----|----|-----------|
157
+ |`x`|`Number`|The number to inspect|
158
+
159
+ Returns:
160
+
161
+ |type|description|
162
+ |----|-----------|
163
+ |`Number`|`-1` if the number is negative, `1` if positive, or `0` otherwise; signedness of `-0.0` is preserved|
164
+
165
+ Examples:
166
+
167
+ ```grain
168
+ Number.sign(-10000) == -1
169
+ ```
170
+
171
+ ```grain
172
+ Number.sign(222222) == 1
173
+ ```
174
+
175
+ ```grain
176
+ Number.sign(0) == 0
177
+ ```
178
+
145
179
  ### Number.**min**
146
180
 
147
181
  <details disabled>