@grain/stdlib 0.4.3 → 0.4.4

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/hash.gr CHANGED
@@ -227,7 +227,7 @@ let rec hashOne = (val, depth) => {
227
227
  *
228
228
  * @since v0.1.0
229
229
  */
230
- export let hash = (anything) => {
230
+ export let rec hash = (anything) => {
231
231
  h = seed
232
232
 
233
233
  hashOne(WasmI32.fromGrain(anything), 0n)
@@ -235,5 +235,10 @@ export let hash = (anything) => {
235
235
 
236
236
  // Tag the number on the way out.
237
237
  // Since Grain has proper modulus, negative numbers are okay.
238
- tagSimpleNumber(h)
238
+ let result = tagSimpleNumber(h)
239
+
240
+ Memory.decRef(WasmI32.fromGrain(hash))
241
+ Memory.decRef(WasmI32.fromGrain(anything))
242
+
243
+ result
239
244
  }
package/list.gr CHANGED
@@ -329,3 +329,57 @@ let join = (separator: String, items: List<String>) => {
329
329
  Some(s) => s,
330
330
  }
331
331
  }
332
+
333
+ /**
334
+ * Reverses the first list and appends the second list to the end.
335
+ *
336
+ * @param list1: The list to reverse
337
+ * @param list2: The list to append
338
+ * @since v0.4.5
339
+ */
340
+ let rec revAppend = (list1, list2) => {
341
+ match (list1) {
342
+ [hd, ...tl] => revAppend(tl, [hd, ...list2]),
343
+ [] => list2
344
+ }
345
+ }
346
+
347
+ /**
348
+ * Sorts the given list based on a given comparator function. The resulting list is sorted in increasing order.
349
+ *
350
+ * Ordering is calculated using a comparator function which takes two list elements and must return 0 if both are equal, a positive number if the first is greater, and a negative number if the first is smaller.
351
+ * @param comp: The comparator function used to indicate sort order
352
+ * @param list: The list to be sorted
353
+ * @since v0.4.5
354
+ */
355
+ let sort = (comp, list) => {
356
+ let rec merge = (left, right, list) => {
357
+ match((left, right)){
358
+ (_, []) => {
359
+ revAppend(list, left)
360
+ },
361
+ ([], _) => {
362
+ revAppend(list, right)
363
+ },
364
+ ([lhd, ...ltl], [rhd, ...rtl]) => {
365
+ if(comp(lhd, rhd) < 0){
366
+ merge(ltl, right, append([lhd],list))
367
+ }else{
368
+ merge(left, rtl, append([rhd], list))
369
+ }
370
+ }
371
+ }
372
+ }
373
+
374
+ let rec mergesort = (list) => {
375
+ if(length(list) <= 1){
376
+ list
377
+ }else{
378
+ let middle = length(list) / 2
379
+ let (left, right) = part(middle, list)
380
+ merge(mergesort(left), mergesort(right), [])
381
+ }
382
+ }
383
+
384
+ mergesort(list)
385
+ }
package/number.gr CHANGED
@@ -15,6 +15,7 @@ import {
15
15
  isFloat,
16
16
  isBoxedNumber
17
17
  } from "runtime/numbers"
18
+ import { parseInt } from "runtime/stringUtils"
18
19
  import { newFloat64, newInt64 } from "runtime/dataStructures"
19
20
  import Tags from "runtime/unsafe/tags"
20
21
 
@@ -76,9 +77,9 @@ export let rec sqrt = (x: Number) => {
76
77
  let x = WasmI32.fromGrain(x)
77
78
  let sqrtd = WasmF64.sqrt(xval)
78
79
  let ret = if (!isFloat(x) && WasmF64.eq(sqrtd, WasmF64.trunc(sqrtd))) {
79
- WasmI32.toGrain(reducedInteger(WasmI64.truncF64S(sqrtd))): Number
80
+ WasmI32.toGrain(reducedInteger(WasmI64.truncF64S(sqrtd))): (Number)
80
81
  } else {
81
- WasmI32.toGrain(newFloat64(sqrtd)): Number
82
+ WasmI32.toGrain(newFloat64(sqrtd)): (Number)
82
83
  }
83
84
  Memory.decRef(WasmI32.fromGrain(x))
84
85
  Memory.decRef(WasmI32.fromGrain(sqrt))
@@ -119,7 +120,7 @@ export let max = (x: Number, y: Number) => if (x > y) x else y
119
120
  export let rec ceil = (x: Number) => {
120
121
  let xval = coerceNumberToWasmF64(x)
121
122
  let ceiling = WasmI64.truncF64S(WasmF64.ceil(xval))
122
- let ret = WasmI32.toGrain(reducedInteger(ceiling)): Number
123
+ let ret = WasmI32.toGrain(reducedInteger(ceiling)): (Number)
123
124
  Memory.decRef(WasmI32.fromGrain(x))
124
125
  Memory.decRef(WasmI32.fromGrain(ceil))
125
126
  ret
@@ -137,7 +138,7 @@ export let rec ceil = (x: Number) => {
137
138
  export let rec floor = (x: Number) => {
138
139
  let xval = coerceNumberToWasmF64(x)
139
140
  let floored = WasmI64.truncF64S(WasmF64.floor(xval))
140
- let ret = WasmI32.toGrain(reducedInteger(floored)): Number
141
+ let ret = WasmI32.toGrain(reducedInteger(floored)): (Number)
141
142
  Memory.decRef(WasmI32.fromGrain(x))
142
143
  Memory.decRef(WasmI32.fromGrain(floor))
143
144
  ret
@@ -155,7 +156,7 @@ export let rec floor = (x: Number) => {
155
156
  export let rec trunc = (x: Number) => {
156
157
  let xval = coerceNumberToWasmF64(x)
157
158
  let trunced = WasmI64.truncF64S(xval)
158
- let ret = WasmI32.toGrain(reducedInteger(trunced)): Number
159
+ let ret = WasmI32.toGrain(reducedInteger(trunced)): (Number)
159
160
  Memory.decRef(WasmI32.fromGrain(x))
160
161
  Memory.decRef(WasmI32.fromGrain(trunc))
161
162
  ret
@@ -173,7 +174,7 @@ export let rec trunc = (x: Number) => {
173
174
  export let rec round = (x: Number) => {
174
175
  let xval = coerceNumberToWasmF64(x)
175
176
  let rounded = WasmI64.truncF64S(WasmF64.nearest(xval))
176
- let ret = WasmI32.toGrain(reducedInteger(rounded)): Number
177
+ let ret = WasmI32.toGrain(reducedInteger(rounded)): (Number)
177
178
  Memory.decRef(WasmI32.fromGrain(x))
178
179
  Memory.decRef(WasmI32.fromGrain(round))
179
180
  ret
@@ -305,3 +306,20 @@ export let rec isInfinite = (x: Number) => {
305
306
  Memory.decRef(WasmI32.fromGrain(isInfinite))
306
307
  ret
307
308
  }
309
+
310
+ /**
311
+ * Parses a string representation of an integer into a `Number` using the
312
+ * specified radix (also known as a number system "base").
313
+ *
314
+ * If the string has a radix prefix (i.e. "0x"/"0X", "0o"/"0O", or "0b"/"0B"
315
+ * for radixes 16, 8, or 2 respectively), the supplied radix is ignored in
316
+ * favor of the prefix. Underscores that appear in the numeric portion of the
317
+ * input are ignored.
318
+ *
319
+ * @param input: The string to parse
320
+ * @param radix: The number system base to use when parsing the input string
321
+ * @returns `Ok(value)` containing the parsed number on a successful parse or `Err(msg)` containing an error message string otherwise
322
+ *
323
+ * @since v0.4.5
324
+ */
325
+ export parseInt
package/number.md CHANGED
@@ -422,3 +422,35 @@ Returns:
422
422
  |----|-----------|
423
423
  |`Bool`|`true` if the value is infinite, otherwise `false`|
424
424
 
425
+ ### Number.**parseInt**
426
+
427
+ <details disabled>
428
+ <summary tabindex="-1">Added in <code>next</code></summary>
429
+ No other changes yet.
430
+ </details>
431
+
432
+ ```grain
433
+ parseInt : (String, Number) -> Result<Number, String>
434
+ ```
435
+
436
+ Parses a string representation of an integer into a `Number` using the
437
+ specified radix (also known as a number system "base").
438
+
439
+ If the string has a radix prefix (i.e. "0x"/"0X", "0o"/"0O", or "0b"/"0B"
440
+ for radixes 16, 8, or 2 respectively), the supplied radix is ignored in
441
+ favor of the prefix. Underscores that appear in the numeric portion of the
442
+ input are ignored.
443
+
444
+ Parameters:
445
+
446
+ |param|type|description|
447
+ |-----|----|-----------|
448
+ |`input`|`String`|The string to parse|
449
+ |`radix`|`Number`|The number system base to use when parsing the input string|
450
+
451
+ Returns:
452
+
453
+ |type|description|
454
+ |----|-----------|
455
+ |`Result<Number, String>`|`Ok(value)` containing the parsed number on a successful parse or `Err(msg)` containing an error message string otherwise|
456
+
package/option.gr CHANGED
@@ -1,78 +1,195 @@
1
- // Standard library for option functionality
1
+ /**
2
+ * @module Option: Utilities for working with the Option data type.
3
+ *
4
+ * The Option type is an enum that represents the possibility of something being present (with the `Some` variant), or not (with the `None` variant). There’s no standalone `null` or `nil` type in Grain; use an Option where you would normally reach for `null` or `nil`.
5
+ *
6
+ * @example import Option from "option"
7
+ *
8
+ * @example let hasValue = Some(1234) // Creates an Option containing 1234
9
+ * @example let noValue = None // Creates an Option containing nothing
10
+ *
11
+ * @since v0.2.0
12
+ */
2
13
 
3
- export *
14
+ /**
15
+ * @section Values: Functions for working with the Option data type.
16
+ */
4
17
 
5
- let isSome = (option) => {
18
+ /**
19
+ * Checks if the Option is the `Some` variant.
20
+ *
21
+ * @param option: The option to check
22
+ * @returns `true` if the Option is the `Some` variant or `false` otherwise
23
+ *
24
+ * @since v0.2.0
25
+ */
26
+ export let isSome = (option) => {
6
27
  match (option) {
7
28
  Some(_) => true,
8
29
  None => false
9
30
  }
10
31
  }
11
32
 
12
- let isNone = (option) => {
33
+ /**
34
+ * Checks if the Option is the `None` variant.
35
+ *
36
+ * @param option: The option to check
37
+ * @returns `true` if the Option is the `None` variant or `false` otherwise
38
+ *
39
+ * @since v0.2.0
40
+ */
41
+ export let isNone = (option) => {
13
42
  match (option) {
14
43
  None => true,
15
44
  Some(_) => false
16
45
  }
17
46
  }
18
47
 
19
- let contains = (val, option) => {
48
+ /**
49
+ * Checks if the Option is the `Some` variant and contains the given value. Uses the generic `==` equality operator.
50
+ *
51
+ * @param value: The value to search for
52
+ * @param option: The option to search
53
+ * @returns `true` if the Option is equivalent to `Some(value)` or `false` otherwise
54
+ *
55
+ * @since v0.2.0
56
+ */
57
+ export let contains = (value, option) => {
20
58
  match (option) {
21
- Some(x) => x == val,
59
+ Some(x) => x == value,
22
60
  None => false
23
61
  }
24
62
  }
25
63
 
26
- let expect = (msg, option) => {
64
+ /**
65
+ * Extracts the value inside a `Some` option, otherwise throws an
66
+ * exception containing the message provided.
67
+ *
68
+ * @param msg: The message to use upon failure
69
+ * @param option: The option to extract a value from
70
+ * @returns The unwrapped value if the Option is the `Some` variant
71
+ *
72
+ * @since v0.2.0
73
+ */
74
+ export let expect = (msg, option) => {
27
75
  match (option) {
28
76
  Some(x) => x,
29
77
  None => fail msg
30
78
  }
31
79
  }
32
80
 
33
- let unwrap = (option) => {
81
+ /**
82
+ * Extracts the value inside a `Some` option, otherwise
83
+ * throws an exception containing a default message.
84
+ *
85
+ * @param option: The option to extract the value from
86
+ * @returns The unwrapped value if the Option is the `Some` variant
87
+ *
88
+ * @since v0.2.0
89
+ */
90
+ export let unwrap = (option) => {
34
91
  expect("Could not unwrap None value", option)
35
92
  }
36
93
 
37
- let unwrapWithDefault = (default, option) => {
94
+ /**
95
+ * Extracts the value inside a `Some` option or provide the default value if `None`.
96
+ *
97
+ * @param default: The default value
98
+ * @param option: The option to unwrap
99
+ * @returns The unwrapped value if the Option is the `Some` variant or the default value otherwise
100
+ *
101
+ * @since v0.2.0
102
+ */
103
+ export let unwrapWithDefault = (default, option) => {
38
104
  match (option) {
39
105
  Some(x) => x,
40
106
  None => default
41
107
  }
42
108
  }
43
109
 
44
- let map = (fn, option) => {
110
+ /**
111
+ * If the Option is `Some(value)`, applies the given function to the `value` and wraps the new value in a `Some` variant.
112
+ *
113
+ * @param fn: The function to call on the value of a `Some` variant
114
+ * @param option: The option to map
115
+ * @returns A new `Some` variant produced by the mapping function if the variant was `Some` or the unmodified `None` otherwise
116
+ *
117
+ * @since v0.2.0
118
+ */
119
+ export let map = (fn, option) => {
45
120
  match (option) {
46
121
  Some(x) => Some(fn(x)),
47
122
  None => None
48
123
  }
49
124
  }
50
125
 
51
- let mapWithDefault = (fn, default, option) => {
126
+ /**
127
+ * If the Option is `Some(value)`, applies the given function to the `value` to produce a new value, otherwise uses the default value.
128
+ * Useful for unwrapping an Option while providing a fallback for any `None` variants.
129
+ *
130
+ * @param fn: The function to call on the value of a `Some` variant
131
+ * @param default: A fallback value for a `None` variant
132
+ * @param option: The option to map
133
+ * @returns The value produced by the mapping function if the Option is of the `Some` variant or the default value otherwise
134
+ *
135
+ * @since v0.2.0
136
+ */
137
+ export let mapWithDefault = (fn, default, option) => {
52
138
  match (option) {
53
139
  Some(x) => fn(x),
54
140
  None => default
55
141
  }
56
142
  }
57
143
 
58
- let mapWithDefaultFn = (fn, defaultFn, option) => {
144
+ /**
145
+ * If the Option is `Some(value)`, applies the `fn` function to the `value` to produce a new value.
146
+ * If the Option is `None`, calls the `defaultFn` function to produce a new value.
147
+ * Useful for unwrapping an Option into a value, whether it is `Some` or `None`.
148
+ *
149
+ * @param fn: The function to call on the value of a `Some` variant
150
+ * @param defaultFn: The default function
151
+ * @param option: The option to map
152
+ * @returns The value produced by one of the mapping functions
153
+ *
154
+ * @since v0.2.0
155
+ */
156
+ export let mapWithDefaultFn = (fn, defaultFn, option) => {
59
157
  match (option) {
60
158
  Some(x) => fn(x),
61
159
  None => defaultFn()
62
160
  }
63
161
  }
64
162
 
65
- let flatMap = (fn, option) => {
163
+ /**
164
+ * If the Option is `Some(value)`, applies the given function to the `value` to produce a new Option.
165
+ *
166
+ * @param fn: The function to call on the value of a `Some` variant
167
+ * @param option: The option to map
168
+ * @returns A new Option produced by the mapping function if the variant was `Some` or the unmodified `None` otherwise
169
+ *
170
+ * @since v0.2.0
171
+ */
172
+ export let flatMap = (fn, option) => {
66
173
  match (option) {
67
174
  Some(x) => fn(x),
68
175
  None => None
69
176
  }
70
177
  }
71
178
 
72
- let filter = (pred, option) => {
179
+ /**
180
+ * Converts `Some(value)` variants to `None` variants where the predicate function returns `false`.
181
+ * if the `fn` return `true` returns `Some(value)`, otherwise returns `None`.
182
+ *
183
+ * @param fn: The predicate function to indicate if the option should remain `Some`
184
+ * @param option: The option to inspect
185
+ * @returns `Some(value)` if the variant was `Some` and the predicate returns `true` or `None` otherwise
186
+ *
187
+ * @since v0.2.0
188
+ */
189
+ export let filter = (fn, option) => {
73
190
  match (option) {
74
191
  Some(x) =>
75
- if (pred(x)) {
192
+ if (fn(x)) {
76
193
  Some(x)
77
194
  } else {
78
195
  None
@@ -81,70 +198,160 @@ let filter = (pred, option) => {
81
198
  }
82
199
  }
83
200
 
84
- let zip = (optionA, optionB) => {
201
+ /**
202
+ * Combine two Options into a single Option containing a tuple of their values.
203
+ *
204
+ * @param optionA: The first option to combine
205
+ * @param optionB: The second option to combine
206
+ * @returns `Some((valueA, valueB))` if both Options are `Some` variants or `None` otherwise
207
+ *
208
+ * @since v0.2.0
209
+ */
210
+ export let zip = (optionA, optionB) => {
85
211
  match ((optionA, optionB)) {
86
212
  (Some(a), Some(b)) => Some((a, b)),
87
213
  _ => None
88
214
  }
89
215
  }
90
216
 
91
- let zipWith = (fn, optionA, optionB) => {
217
+ /**
218
+ * Combine two Options into a single Option. The new value is produced by applying the given function to both values.
219
+ *
220
+ * @param fn: The function to generate a new value
221
+ * @param optionA: The first option to combine
222
+ * @param optionB: The second option to combine
223
+ * @returns `Some(newValue)` if both Options are `Some` variants or `None` otherwise
224
+ *
225
+ * @since v0.2.0
226
+ */
227
+ export let zipWith = (fn, optionA, optionB) => {
92
228
  match ((optionA, optionB)) {
93
229
  (Some(a), Some(b)) => Some(fn(a, b)),
94
230
  _ => None
95
231
  }
96
232
  }
97
233
 
98
- let flatten = (option) => {
234
+ /**
235
+ * Flattens nested Options.
236
+ *
237
+ * @param option: The option to flatten
238
+ * @returns `Some(innerValue)` if all nested options were the `Some` variant or `None` otherwise
239
+ *
240
+ * @example Option.flatten(Some(Some(1))) == Some(1)
241
+ *
242
+ * @since v0.2.0
243
+ */
244
+ export let flatten = (option) => {
99
245
  match (option) {
100
246
  Some(Some(x)) => Some(x),
101
247
  _ => None
102
248
  }
103
249
  }
104
250
 
105
- let toList = (option) => {
251
+ /**
252
+ * Converts an Option to a list with either zero or one item.
253
+ *
254
+ * @param option: The option to convert
255
+ * @returns `[value]` if the Option was the `Some` variant or `[]` otherwise
256
+ *
257
+ * @since v0.2.0
258
+ */
259
+ export let toList = (option) => {
106
260
  match (option) {
107
261
  Some(x) => [x],
108
262
  None => []
109
263
  }
110
264
  }
111
265
 
112
- let toArray = (option) => {
266
+ /**
267
+ * Converts an Option to an array with either zero or one item.
268
+ *
269
+ * @param option: The option to convert
270
+ * @returns `[> value]` if the Option was the `Some` variant or `[> ]` otherwise
271
+ *
272
+ * @since v0.2.0
273
+ */
274
+ export let toArray = (option) => {
113
275
  match (option) {
114
276
  Some(x) => [> x],
115
277
  None => [>]
116
278
  }
117
279
  }
118
280
 
119
- let sideEffect = (fn, option) => {
281
+ /**
282
+ * Converts the Option to a Result, using the provided error in case of the `None` variant.
283
+ *
284
+ * @param err: The error to use if the option is `None`
285
+ * @param option: The option to convert
286
+ * @returns `Ok(value)` if the Option is `Some(value)` or `Err(err)` if the Option is `None`
287
+ *
288
+ * @since v0.2.0
289
+ */
290
+ export let toResult = (err, option) => {
291
+ match (option) {
292
+ Some(a) => Ok(a),
293
+ None => Err(err)
294
+ }
295
+ }
296
+
297
+ /**
298
+ * If the Option is `Some(value)`, applies the `fn` function to the `value` without producing a new value.
299
+ *
300
+ * @param fn: The function to call on the value of a `Some` variant
301
+ * @param option: The option to inspect
302
+ *
303
+ * @since v0.2.0
304
+ */
305
+ export let sideEffect = (fn, option) => {
120
306
  match (option) {
121
307
  Some(x) => fn(x),
122
308
  None => void
123
309
  }
124
310
  }
125
311
 
126
- let peek = (fn, option) => {
312
+ /**
313
+ * If the Option is `Some(value)`, applies the `fn` function to the `value` without producing a new value.
314
+ * Useful for inspecting Options without changing anything.
315
+ *
316
+ * @param fn: The function to call on the value of a `Some` variant
317
+ * @param option: The option to inspect
318
+ * @returns The unmodified option
319
+ *
320
+ * @since v0.2.0
321
+ */
322
+ export let peek = (fn, option) => {
127
323
  sideEffect(fn, option)
128
324
  option
129
325
  }
130
326
 
131
- let or = (r1, r2) => {
132
- match (r1) {
133
- Some(x) => r1,
134
- None => r2
327
+ /**
328
+ * Behaves like a logical OR (`||`) where the first Option is only returned if it is the `Some` variant and falling back to the second Option in all other cases.
329
+ *
330
+ * @param optionA: The first option
331
+ * @param optionB: The second option
332
+ * @returns The first Option if it is the `Some` variant or the second Option otherwise
333
+ *
334
+ * @since v0.2.0
335
+ */
336
+ export let or = (optionA, optionB) => {
337
+ match (optionA) {
338
+ Some(x) => optionA,
339
+ None => optionB
135
340
  }
136
341
  }
137
342
 
138
- let and = (r1, r2) => {
139
- match (r1) {
140
- Some(_) => r2,
141
- None => r1
142
- }
143
- }
144
-
145
- let toResult = (err, option) => {
146
- match (option) {
147
- Some(a) => Ok(a),
148
- None => Err(err)
343
+ /**
344
+ * Behaves like a logical AND (`&&`) where the first Option is only returned if it is the `None` variant and falling back to the second Option Result in all other cases.
345
+ *
346
+ * @param optionA: The first option
347
+ * @param optionB: The second option
348
+ * @returns The second Option if both are the `Some` variant or the first Option otherwise
349
+ *
350
+ * @since v0.2.0
351
+ */
352
+ export let and = (optionA, optionB) => {
353
+ match (optionA) {
354
+ Some(_) => optionB,
355
+ None => optionA
149
356
  }
150
357
  }