functionalscript 0.0.487 → 0.0.489
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/README.md +4 -2
- package/com/cpp/module.f.cjs +1 -2
- package/com/cpp/test.f.cjs +1 -1
- package/com/cpp/testlib.f.cjs +1 -1
- package/com/test/build.f.cjs +1 -1
- package/commonjs/build/module.f.cjs +1 -1
- package/commonjs/build/test.f.cjs +2 -1
- package/commonjs/module/module.f.cjs +1 -1
- package/commonjs/path/module.f.cjs +5 -5
- package/dev/test.mjs +1 -1
- package/doc/predefined.md +2 -2
- package/fsc/test.f.cjs +1 -1
- package/json/module.f.cjs +4 -4
- package/package.json +1 -1
- package/text/README.md +2 -2
- package/text/utf8/module.f.cjs +15 -15
- package/types/array/module.f.cjs +9 -9
- package/types/array/test.f.cjs +1 -2
- package/types/btree/find/module.f.cjs +3 -3
- package/types/btree/module.f.cjs +2 -2
- package/types/btree/remove/module.f.cjs +11 -11
- package/types/btree/remove/test.f.cjs +52 -52
- package/types/btree/set/module.f.cjs +6 -6
- package/types/btree/test.f.cjs +2 -2
- package/types/btree/types/module.f.cjs +1 -1
- package/types/byte_set/module.f.cjs +8 -9
- package/types/list/module.f.cjs +61 -66
- package/types/list/test.f.cjs +9 -9
- package/types/map/module.f.cjs +7 -6
- package/types/map/test.f.cjs +9 -9
- package/types/nullable/module.f.cjs +17 -0
- package/types/{option → nullable}/test.f.cjs +2 -2
- package/types/number/module.f.cjs +2 -2
- package/types/number/test.f.cjs +1 -1
- package/types/range_map/module.f.cjs +6 -6
- package/types/range_map/test.f.cjs +2 -2
- package/types/sorted_list/module.f.cjs +13 -15
- package/types/sorted_list/test.f.cjs +2 -2
- package/types/sorted_set/module.f.cjs +4 -4
- package/types/sorted_set/test.f.cjs +0 -1
- package/types/string_set/module.f.cjs +2 -2
- package/types/string_set/test.f.cjs +3 -3
- package/types/option/module.f.cjs +0 -17
package/types/list/module.f.cjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
const
|
|
1
|
+
const function_ = require('../function/module.f.cjs')
|
|
2
|
+
const { identity, fn, compose } = function_
|
|
2
3
|
const operator = require('../function/operator/module.f.cjs')
|
|
3
4
|
const {
|
|
4
5
|
counter,
|
|
@@ -23,7 +24,7 @@ const {
|
|
|
23
24
|
* } NotLazy
|
|
24
25
|
*/
|
|
25
26
|
|
|
26
|
-
/** @typedef {
|
|
27
|
+
/** @typedef {null} Empty */
|
|
27
28
|
|
|
28
29
|
/**
|
|
29
30
|
* @template T
|
|
@@ -46,8 +47,8 @@ const {
|
|
|
46
47
|
/**
|
|
47
48
|
* @template T
|
|
48
49
|
* @typedef {{
|
|
49
|
-
* readonly
|
|
50
|
-
* readonly
|
|
50
|
+
* readonly head: List<T>
|
|
51
|
+
* readonly tail: List<T>
|
|
51
52
|
* }} Concat
|
|
52
53
|
*/
|
|
53
54
|
|
|
@@ -55,41 +56,40 @@ const {
|
|
|
55
56
|
const fromArray = array => {
|
|
56
57
|
/** @typedef {typeof array extends readonly (infer T)[] ? T : never} T */
|
|
57
58
|
/** @type {(i: number) => Result<T>} */
|
|
58
|
-
const at = i => i < array.length ? { first: array[i], tail: () => at(i + 1) } :
|
|
59
|
+
const at = i => i < array.length ? { first: array[i], tail: () => at(i + 1) } : null
|
|
59
60
|
return at(0)
|
|
60
61
|
}
|
|
61
62
|
|
|
62
|
-
/** @type {<T>(
|
|
63
|
-
const concat =
|
|
63
|
+
/** @type {<T>(head: List<T>) => (tail: List<T>) => List<T>} */
|
|
64
|
+
const concat = head => tail => tail === null ? head : ({ head, tail })
|
|
64
65
|
|
|
65
66
|
/** @type {<T>(list: List<T>) => NotLazy<T> } */
|
|
66
67
|
const trampoline = list => {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
return i
|
|
68
|
+
while (typeof list === 'function') { list = list() }
|
|
69
|
+
return list
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
/** @type {<T>(list: List<T>) => Result<T>} */
|
|
73
|
-
const next =
|
|
74
|
-
/** @type {
|
|
75
|
-
let
|
|
73
|
+
const next = head => {
|
|
74
|
+
/** @type {typeof head} */
|
|
75
|
+
let tail = null
|
|
76
76
|
while (true) {
|
|
77
|
-
|
|
77
|
+
head = trampoline(head)
|
|
78
78
|
|
|
79
|
-
if (
|
|
80
|
-
|
|
81
|
-
} else if (
|
|
82
|
-
[
|
|
79
|
+
if (head instanceof Array) {
|
|
80
|
+
head = fromArray(head)
|
|
81
|
+
} else if (head !== null && 'head' in head) {
|
|
82
|
+
[head, tail] = [head.head, concat(head.tail)(tail)]
|
|
83
83
|
continue
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
if (
|
|
87
|
-
return { first:
|
|
86
|
+
if (head !== null) {
|
|
87
|
+
return { first: head.first, tail: concat(head.tail)(tail) }
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
if (
|
|
90
|
+
if (tail === null) { return null }
|
|
91
91
|
|
|
92
|
-
[
|
|
92
|
+
[head, tail] = [tail, null]
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
95
|
|
|
@@ -99,7 +99,7 @@ const iterable = list => ({
|
|
|
99
99
|
let i = list
|
|
100
100
|
while (true) {
|
|
101
101
|
const r = next(i)
|
|
102
|
-
if (r ===
|
|
102
|
+
if (r === null) { return }
|
|
103
103
|
yield r.first
|
|
104
104
|
i = r.tail
|
|
105
105
|
}
|
|
@@ -117,18 +117,18 @@ const toArray = list => {
|
|
|
117
117
|
/** @type {<I, O>(step: (n: NonEmpty<I>) => List<O>) => (input: List<I>) => Thunk<O>} */
|
|
118
118
|
const apply = f => input => () => {
|
|
119
119
|
const n = next(input)
|
|
120
|
-
if (n ===
|
|
120
|
+
if (n === null) { return null }
|
|
121
121
|
return f(n)
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
/** @type {<T>(n: NonEmpty<List<T>>) => List<T>} */
|
|
125
|
-
const flatStep =
|
|
125
|
+
const flatStep = ({ first, tail }) => concat(first)(flat(tail))
|
|
126
126
|
|
|
127
127
|
/** @type {<T>(list: List<List<T>>) => Thunk<T>} */
|
|
128
128
|
const flat = apply(flatStep)
|
|
129
129
|
|
|
130
130
|
/** @type {<I, O>(f: (value: I) => O) => (n: NonEmpty<I>) => List<O>} */
|
|
131
|
-
const mapStep = f =>
|
|
131
|
+
const mapStep = f => ({ first, tail }) => ({ first: f(first), tail: map(f)(tail) })
|
|
132
132
|
|
|
133
133
|
/** @type {<I, O>(f: (value: I) => O) => (input: List<I>) => Thunk<O>} */
|
|
134
134
|
const map = f => apply(mapStep(f))
|
|
@@ -137,31 +137,31 @@ const map = f => apply(mapStep(f))
|
|
|
137
137
|
const flatMap = f => compose(map(f))(flat)
|
|
138
138
|
|
|
139
139
|
/** @type {<T>(f: (value: T) => boolean) => (n: NonEmpty<T>) => List<T>} */
|
|
140
|
-
const filterStep = f =>
|
|
141
|
-
const
|
|
142
|
-
return f(
|
|
140
|
+
const filterStep = f => ({ first, tail }) => {
|
|
141
|
+
const newTail = filter(f)(tail)
|
|
142
|
+
return f(first) ? { first, tail: newTail } : newTail
|
|
143
143
|
}
|
|
144
144
|
|
|
145
145
|
/** @type {<T>(f: (value: T) => boolean) => (input: List<T>) => Thunk<T>} */
|
|
146
146
|
const filter = f => apply(filterStep(f))
|
|
147
147
|
|
|
148
|
-
/** @type {<I, O>(f: (value: I) => O|
|
|
148
|
+
/** @type {<I, O>(f: (value: I) => O|null) => (n: NonEmpty<I>) => List<O>} */
|
|
149
149
|
const filterMapStep = f => n => {
|
|
150
150
|
const [first, tail] = [f(n.first), filterMap(f)(n.tail)]
|
|
151
|
-
return first ===
|
|
151
|
+
return first === null ? tail : { first, tail }
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
-
/** @type {<I, O>(f: (value: I) => O|
|
|
154
|
+
/** @type {<I, O>(f: (value: I) => O|null) => (input: List<I>) => Thunk<O>} */
|
|
155
155
|
const filterMap = f => apply(filterMapStep(f))
|
|
156
156
|
|
|
157
157
|
/** @type {<T>(f: (value: T) => boolean) => (n: NonEmpty<T>) => List<T>} */
|
|
158
|
-
const takeWhileStep = f =>
|
|
158
|
+
const takeWhileStep = f => ({ first, tail }) => f(first) ? { first, tail: takeWhile(f)(tail) } : null
|
|
159
159
|
|
|
160
160
|
/** @type {<T>(f: (value: T) => boolean) => (input: List<T>) => Thunk<T>} */
|
|
161
161
|
const takeWhile = f => apply(takeWhileStep(f))
|
|
162
162
|
|
|
163
163
|
/** @type {(n: number) => <T>(result: NonEmpty<T>) => List<T>} */
|
|
164
|
-
const takeStep = n =>
|
|
164
|
+
const takeStep = n => ({ first, tail }) => 0 < n ? { first: first, tail: take(n - 1)(tail) } : null
|
|
165
165
|
|
|
166
166
|
/** @type {(n: number) => <T>(input: List<T>) => Thunk<T>} */
|
|
167
167
|
const take = n => apply(takeStep(n))
|
|
@@ -180,8 +180,8 @@ const drop = n => apply(dropStep(n))
|
|
|
180
180
|
|
|
181
181
|
/** @type {<D>(def: D) => <T>(input: List<T>) => D|T} */
|
|
182
182
|
const first = def => input => {
|
|
183
|
-
const
|
|
184
|
-
return
|
|
183
|
+
const ne = next(input)
|
|
184
|
+
return ne === null ? def : ne.first
|
|
185
185
|
}
|
|
186
186
|
|
|
187
187
|
/** @type {<D>(first: D) => <T>(tail: List<T>) => D|T} */
|
|
@@ -191,7 +191,7 @@ const last = first => tail => {
|
|
|
191
191
|
let i = { first, tail }
|
|
192
192
|
while (true) {
|
|
193
193
|
const result = next(i.tail)
|
|
194
|
-
if (result ===
|
|
194
|
+
if (result === null) {
|
|
195
195
|
return i.first
|
|
196
196
|
}
|
|
197
197
|
i = result
|
|
@@ -199,43 +199,39 @@ const last = first => tail => {
|
|
|
199
199
|
}
|
|
200
200
|
|
|
201
201
|
/** @type {<D>(def: D) => <T>(f: (value: T) => boolean) => (input: List<T>) => D|T} */
|
|
202
|
-
const find = def => f =>
|
|
203
|
-
|
|
204
|
-
const findTrue = find(false)
|
|
202
|
+
const find = def => f => compose(filter(f))(first(def))
|
|
205
203
|
|
|
206
204
|
/** @type {(input: List<boolean>) => boolean} */
|
|
207
|
-
const some =
|
|
208
|
-
(/** @type {(_: boolean) => boolean} */(identity))
|
|
209
|
-
(input)
|
|
210
|
-
|
|
211
|
-
/** @type {<T>(f: List<T>) => Thunk<boolean>} */
|
|
212
|
-
const mapTrue = map(() => true)
|
|
205
|
+
const some = find(false)(identity)
|
|
213
206
|
|
|
214
207
|
/** @type {<T>(input: List<T>) => boolean} */
|
|
215
|
-
const isEmpty =
|
|
208
|
+
const isEmpty = fn(map(() => true))
|
|
209
|
+
.then(some)
|
|
210
|
+
.then(logicalNot)
|
|
211
|
+
.result
|
|
216
212
|
|
|
217
|
-
const
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
213
|
+
const every = fn(map(logicalNot))
|
|
214
|
+
.then(some)
|
|
215
|
+
.then(logicalNot)
|
|
216
|
+
.result
|
|
221
217
|
|
|
222
218
|
/** @type {<T>(value: T) => (sequence: List<T>) => boolean} */
|
|
223
|
-
const includes = value =>
|
|
219
|
+
const includes = value => compose(map(strictEqual(value)))(some)
|
|
224
220
|
|
|
225
221
|
/** @type {(count: number) => Thunk<number>} */
|
|
226
222
|
const countdown = count => () => {
|
|
227
|
-
if (count <= 0) { return
|
|
223
|
+
if (count <= 0) { return null }
|
|
228
224
|
const first = count - 1
|
|
229
225
|
return { first, tail: countdown(first) }
|
|
230
226
|
}
|
|
231
227
|
|
|
232
228
|
/** @type {<T>(v: T) => (c: number) => Thunk<T>} */
|
|
233
|
-
const repeat = v =>
|
|
229
|
+
const repeat = v => compose(countdown)(map(() => v))
|
|
234
230
|
|
|
235
231
|
/** @type {<T>(list: List<T>) => List<T>} */
|
|
236
232
|
const cycle = list => () => {
|
|
237
233
|
const i = next(list)
|
|
238
|
-
return i ===
|
|
234
|
+
return i === null ? null : { first: i.first, tail: concat(i.tail)(cycle(list)) }
|
|
239
235
|
}
|
|
240
236
|
|
|
241
237
|
/** @type {<I, O>(op: operator.Scan<I, O>) => (ne: NonEmpty<I>) => List<O>} */
|
|
@@ -248,17 +244,16 @@ const scanStep = op => ne => {
|
|
|
248
244
|
const scan = op => apply(scanStep(op))
|
|
249
245
|
|
|
250
246
|
/** @type {<I, S, O>(op: operator.StateScan<I, S, O>) => (init: S) => (input: List<I>) => Thunk<O>} */
|
|
251
|
-
const stateScan = op =>
|
|
247
|
+
const stateScan = op => compose(stateScanToScan(op))(scan)
|
|
252
248
|
|
|
253
249
|
/** @type {<I,O>(op: operator.Fold<I, O>) => (init: O) => (input: List<I>) => Thunk<O>} */
|
|
254
|
-
const foldScan = op =>
|
|
250
|
+
const foldScan = op => compose(foldToScan(op))(scan)
|
|
255
251
|
|
|
256
252
|
/** @type {<I,O>(op: operator.Fold<I, O>) => (init: O) => (input: List<I>) => O} */
|
|
257
|
-
const fold = op => init =>
|
|
253
|
+
const fold = op => init => compose(foldScan(op)(init))(last(init))
|
|
258
254
|
|
|
259
255
|
/** @type {<T>(op: operator.Reduce<T>) => <D>(def: D) => (input: List<T>) => D|T} */
|
|
260
|
-
const reduce = op => def =>
|
|
261
|
-
|
|
256
|
+
const reduce = op => def => compose(scan(reduceToScan(op)))(last(def))
|
|
262
257
|
|
|
263
258
|
/** @type {<T>(input: List<T>) => number} */
|
|
264
259
|
const length = fold(counter)(0)
|
|
@@ -283,14 +278,14 @@ const entries = input => {
|
|
|
283
278
|
const reverseOperator = first => tail => ({ first, tail })
|
|
284
279
|
|
|
285
280
|
/** @type {<T>(input: List<T>) => List<T>} */
|
|
286
|
-
const reverse = fold(reverseOperator)(
|
|
281
|
+
const reverse = fold(reverseOperator)(null)
|
|
287
282
|
|
|
288
283
|
/** @type {<A>(a: List<A>) => <B>(b: List<B>) => List<readonly[A, B]>} */
|
|
289
284
|
const zip = a => b => () => {
|
|
290
285
|
const aResult = next(a)
|
|
291
|
-
if (aResult ===
|
|
286
|
+
if (aResult === null) { return null }
|
|
292
287
|
const bResult = next(b)
|
|
293
|
-
if (bResult ===
|
|
288
|
+
if (bResult === null) { return null }
|
|
294
289
|
return { first: [aResult.first, bResult.first], tail: zip(aResult.tail)(bResult.tail) }
|
|
295
290
|
}
|
|
296
291
|
|
|
@@ -300,8 +295,8 @@ const equal = e => {
|
|
|
300
295
|
/** @type {(a: List<T>) => (b: List<T>) => List<boolean>} */
|
|
301
296
|
const f = a => b => () => {
|
|
302
297
|
const [aResult, bResult] = [next(a), next(b)]
|
|
303
|
-
return aResult ===
|
|
304
|
-
? { first: aResult === bResult, tail:
|
|
298
|
+
return aResult === null || bResult === null
|
|
299
|
+
? { first: aResult === bResult, tail: null }
|
|
305
300
|
: { first: e(aResult.first)(bResult.first), tail: f(aResult.tail)(bResult.tail) }
|
|
306
301
|
}
|
|
307
302
|
return a => b => every(f(a)(b))
|
|
@@ -309,7 +304,7 @@ const equal = e => {
|
|
|
309
304
|
|
|
310
305
|
module.exports = {
|
|
311
306
|
/** @readonly */
|
|
312
|
-
empty:
|
|
307
|
+
empty: null,
|
|
313
308
|
/** @readonly */
|
|
314
309
|
concat,
|
|
315
310
|
/** @readonly */
|
package/types/list/test.f.cjs
CHANGED
|
@@ -29,7 +29,7 @@ const flat = () => {
|
|
|
29
29
|
const concat = () => {
|
|
30
30
|
const result = _.concat([1])([2])
|
|
31
31
|
const x = _.next(result)
|
|
32
|
-
if (x ===
|
|
32
|
+
if (x === null) { throw x }
|
|
33
33
|
if (x.first !== 1) { throw x }
|
|
34
34
|
}
|
|
35
35
|
|
|
@@ -55,11 +55,11 @@ const take = [
|
|
|
55
55
|
|
|
56
56
|
const find = [
|
|
57
57
|
() => {
|
|
58
|
-
const result = _.find(
|
|
59
|
-
if (result !==
|
|
58
|
+
const result = _.find(null)(x => x % 2 === 0)([1, 3, 5, 7])
|
|
59
|
+
if (result !== null) { throw result }
|
|
60
60
|
},
|
|
61
61
|
() => {
|
|
62
|
-
const result = _.find(
|
|
62
|
+
const result = _.find(null)(x => x % 2 === 0)([1, 2, 3, 4])
|
|
63
63
|
if (result !== 2) { throw result }
|
|
64
64
|
}
|
|
65
65
|
]
|
|
@@ -102,12 +102,12 @@ const additionTests = [
|
|
|
102
102
|
if (result !== '[2,5,9,14]') { throw result }
|
|
103
103
|
},
|
|
104
104
|
() => {
|
|
105
|
-
const result = _.reduce(addition)(
|
|
105
|
+
const result = _.reduce(addition)(null)([2, 3, 4, 5])
|
|
106
106
|
if (result !== 14) { throw result }
|
|
107
107
|
},
|
|
108
108
|
() => {
|
|
109
|
-
const result = _.reduce(addition)(
|
|
110
|
-
if (result !==
|
|
109
|
+
const result = _.reduce(addition)(null)([])
|
|
110
|
+
if (result !== null) { throw result }
|
|
111
111
|
}
|
|
112
112
|
]
|
|
113
113
|
|
|
@@ -191,7 +191,7 @@ const stress = () => ({
|
|
|
191
191
|
const n = 50_000_000
|
|
192
192
|
const result = _.toArray(_.countdown(n))
|
|
193
193
|
if (result.length !== n) { throw result.length }
|
|
194
|
-
const first = _.first(
|
|
194
|
+
const first = _.first(null)(result)
|
|
195
195
|
if (first !== n - 1) { throw first }
|
|
196
196
|
},
|
|
197
197
|
concatBack: () => {
|
|
@@ -244,7 +244,7 @@ const stress = () => ({
|
|
|
244
244
|
const n = 50_000_000
|
|
245
245
|
const result = _.toArray(_.countdown(n))
|
|
246
246
|
if (result.length !== n) { throw result.length }
|
|
247
|
-
const len = _.length(_.filterMap(() =>
|
|
247
|
+
const len = _.length(_.filterMap(() => null)(result))
|
|
248
248
|
if (len !== 0) { throw len }
|
|
249
249
|
},
|
|
250
250
|
dropWhile: () => {
|
package/types/map/module.f.cjs
CHANGED
|
@@ -31,15 +31,16 @@ const operator = require('../function/operator/module.f.cjs')
|
|
|
31
31
|
/** @type {(a: string) => <T>(b: Entry<T>) => Sign} */
|
|
32
32
|
const keyCmp = a => ([b]) => cmp(a)(b)
|
|
33
33
|
|
|
34
|
-
/** @type {(name: string) => <T>(map: Map<T>) => T|
|
|
34
|
+
/** @type {(name: string) => <T>(map: Map<T>) => T|null} */
|
|
35
35
|
const at = name => map => {
|
|
36
|
-
if (map ===
|
|
36
|
+
if (map === null) { return null }
|
|
37
37
|
const result = value(find(keyCmp(name))(map).first)
|
|
38
|
-
return result ===
|
|
38
|
+
return result === null ? null : result[1]
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
/** @type {<T>(reduce: operator.Reduce<T>) => (entry: Entry<T>) => (map: Map<T>) => Map<T>} */
|
|
42
|
-
const setReduceEntry = reduce => entry =>
|
|
42
|
+
const setReduceEntry = reduce => entry =>
|
|
43
|
+
set(keyCmp(entry[0]))(old => old === null ? entry : [old[0], reduce(old[1])(entry[1])])
|
|
43
44
|
|
|
44
45
|
/** @type {<T>(reduce: operator.Reduce<T>) => (name: string) => (value: T) => (map: Map<T>) => Map<T>} */
|
|
45
46
|
const setReduce = reduce => name => value => setReduceEntry(reduce)([name, value])
|
|
@@ -54,14 +55,14 @@ const setReplace = name => value => setReduceEntry(replace)([name, value])
|
|
|
54
55
|
const entries = values
|
|
55
56
|
|
|
56
57
|
/** @type {<T>(entries: list.List<Entry<T>>) => Map<T>} */
|
|
57
|
-
const fromEntries = fold(setReduceEntry(replace))(
|
|
58
|
+
const fromEntries = fold(setReduceEntry(replace))(null)
|
|
58
59
|
|
|
59
60
|
/** @type {(name: string) => <T>(map: Map<T>) => Map<T>} */
|
|
60
61
|
const remove = name => btreeRemove(keyCmp(name))
|
|
61
62
|
|
|
62
63
|
module.exports = {
|
|
63
64
|
/** @readonly */
|
|
64
|
-
empty:
|
|
65
|
+
empty: null,
|
|
65
66
|
/** @readonly */
|
|
66
67
|
at,
|
|
67
68
|
/** @readonly */
|
package/types/map/test.f.cjs
CHANGED
|
@@ -4,23 +4,23 @@ const seq = require('../list/module.f.cjs')
|
|
|
4
4
|
module.exports = {
|
|
5
5
|
main: [
|
|
6
6
|
() => {
|
|
7
|
-
let m = setReplace('a')(1)(
|
|
7
|
+
let m = setReplace('a')(1)(null)
|
|
8
8
|
|
|
9
9
|
if (at('a')(m) !== 1) { throw 'error' }
|
|
10
|
-
if (at('b')(m) !==
|
|
10
|
+
if (at('b')(m) !== null) { throw 'error' }
|
|
11
11
|
|
|
12
12
|
m = setReplace('b')(2)(m)
|
|
13
13
|
|
|
14
14
|
if (at('a')(m) !== 1) { throw 'error' }
|
|
15
15
|
if (at('b')(m) !== 2) { throw 'error' }
|
|
16
|
-
if (at('c')(m) !==
|
|
16
|
+
if (at('c')(m) !== null) { throw 'error' }
|
|
17
17
|
|
|
18
18
|
m = setReplace('z')(3)(m)
|
|
19
19
|
|
|
20
20
|
if (at('a')(m) !== 1) { throw 'error' }
|
|
21
21
|
if (at('b')(m) !== 2) { throw 'error' }
|
|
22
22
|
if (at('z')(m) !== 3) { throw 'error' }
|
|
23
|
-
if (at('')(m) !==
|
|
23
|
+
if (at('')(m) !== null) { throw 'error' }
|
|
24
24
|
|
|
25
25
|
m = setReplace('')(4)(m)
|
|
26
26
|
|
|
@@ -28,7 +28,7 @@ module.exports = {
|
|
|
28
28
|
if (at('b')(m) !== 2) { throw 'error' }
|
|
29
29
|
if (at('z')(m) !== 3) { throw 'error' }
|
|
30
30
|
if (at('')(m) !== 4) { throw 'error' }
|
|
31
|
-
if (at('Hello world!')(m) !==
|
|
31
|
+
if (at('Hello world!')(m) !== null) { throw 'error' }
|
|
32
32
|
|
|
33
33
|
m = setReplace('Hello world!')(42)(m)
|
|
34
34
|
|
|
@@ -37,21 +37,21 @@ module.exports = {
|
|
|
37
37
|
if (at('z')(m) !== 3) { throw 'error' }
|
|
38
38
|
if (at('')(m) !== 4) { throw 'error' }
|
|
39
39
|
if (at('Hello world!')(m) !== 42) { throw 'error' }
|
|
40
|
-
if (at('x')(m) !==
|
|
40
|
+
if (at('x')(m) !== null) { throw 'error' }
|
|
41
41
|
|
|
42
42
|
// console.log(Array.from(m.entries()))
|
|
43
43
|
m = remove('Hello world!')(m)
|
|
44
|
-
if (at('Hello world!')(m) !==
|
|
44
|
+
if (at('Hello world!')(m) !== null) { throw m }
|
|
45
45
|
|
|
46
46
|
m = setReduce(a => b => a + b)('a')(43)(m)
|
|
47
47
|
if (at('a')(m) !== 44) { throw 'error' }
|
|
48
48
|
},
|
|
49
49
|
() => {
|
|
50
|
-
let m = setReplace('x')(12)(
|
|
50
|
+
let m = setReplace('x')(12)(null)
|
|
51
51
|
m = setReplace('y')(44)(m)
|
|
52
52
|
if (at('x')(m) !== 12) { throw 'error' }
|
|
53
53
|
if (at('y')(m) !== 44) { throw 'error' }
|
|
54
|
-
if (at('a')(m) !==
|
|
54
|
+
if (at('a')(m) !== null) { throw 'error' }
|
|
55
55
|
const e = seq.toArray(entries(m))
|
|
56
56
|
if (e.length !== 2) { throw 'error' }
|
|
57
57
|
},
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @template T
|
|
3
|
+
* @typedef {T|null} Nullable
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/** @type {<T, R>(f: (value: T) => R) => (value: Nullable<T>) => Nullable<R>} */
|
|
7
|
+
const map = f => value => value === null ? null : f(value)
|
|
8
|
+
|
|
9
|
+
/** @type {<T, R>(f: (_: T) => R) => (none: () => R) => (_: Nullable<T>) => Nullable<R>} */
|
|
10
|
+
const match = f => none => value => value === null ? none() : f(value)
|
|
11
|
+
|
|
12
|
+
module.exports = {
|
|
13
|
+
/** @readonly */
|
|
14
|
+
map,
|
|
15
|
+
/** @readonly */
|
|
16
|
+
match,
|
|
17
|
+
}
|
|
@@ -4,6 +4,6 @@ module.exports = () => {
|
|
|
4
4
|
const optionSq = _.map(v => v * v)
|
|
5
5
|
const sq3 = optionSq(3)
|
|
6
6
|
if (sq3 !== 9) { throw sq3 }
|
|
7
|
-
const
|
|
8
|
-
if (
|
|
7
|
+
const sqNull = optionSq(null)
|
|
8
|
+
if (sqNull !== null) { throw sqNull }
|
|
9
9
|
}
|
|
@@ -5,9 +5,9 @@ const { unsafeCmp } = compare
|
|
|
5
5
|
|
|
6
6
|
const sum = reduce(addition)(0)
|
|
7
7
|
|
|
8
|
-
const min = reduce(minOp)(
|
|
8
|
+
const min = reduce(minOp)(null)
|
|
9
9
|
|
|
10
|
-
const max = reduce(maxOp)(
|
|
10
|
+
const max = reduce(maxOp)(null)
|
|
11
11
|
|
|
12
12
|
/** @type {(a: number) => (b: number) => compare.Sign} */
|
|
13
13
|
const cmp = unsafeCmp
|
package/types/number/test.f.cjs
CHANGED
|
@@ -2,7 +2,7 @@ const sortedList = require("../sorted_list/module.f.cjs")
|
|
|
2
2
|
const { genericMerge } = sortedList
|
|
3
3
|
const list = require("../list/module.f.cjs")
|
|
4
4
|
const { next } = list
|
|
5
|
-
const option = require("../
|
|
5
|
+
const option = require("../nullable/module.f.cjs")
|
|
6
6
|
const { cmp } = require('../number/module.f.cjs')
|
|
7
7
|
const operator = require("../function/operator/module.f.cjs")
|
|
8
8
|
const _range = require('../range/module.f.cjs')
|
|
@@ -32,7 +32,7 @@ const _range = require('../range/module.f.cjs')
|
|
|
32
32
|
|
|
33
33
|
/**
|
|
34
34
|
* @template T
|
|
35
|
-
* @typedef {option.
|
|
35
|
+
* @typedef {option.Nullable<Entry<T>>} RangeState
|
|
36
36
|
*/
|
|
37
37
|
|
|
38
38
|
/**
|
|
@@ -45,21 +45,21 @@ const reduceOp = union => equal => state => ([aItem, aMax]) => ([bItem, bMax])
|
|
|
45
45
|
const sign = cmp(aMax)(bMax)
|
|
46
46
|
const min = sign === 1 ? bMax : aMax
|
|
47
47
|
const u = union(aItem)(bItem)
|
|
48
|
-
const newState = state !==
|
|
48
|
+
const newState = state !== null && equal(state[0])(u) ? null : state
|
|
49
49
|
return [newState, sign, [u, min]]
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
/** @type {<T>(equal: operator.Equal<T>) => sortedList.TailReduce<Entry<T>, RangeState<T>>} */
|
|
53
53
|
const tailReduce = equal => state => tail => {
|
|
54
|
-
if (state ===
|
|
54
|
+
if (state === null) { return tail }
|
|
55
55
|
const tailResult = next(tail)
|
|
56
|
-
if (tailResult ===
|
|
56
|
+
if (tailResult === null) { return [state] }
|
|
57
57
|
if (equal(state[0])(tailResult.first[0])) { return tailResult }
|
|
58
58
|
return { first: state, tail: tailResult }
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
/** @type {<T>(op: Operators<T>) => RangeMerge<T>} */
|
|
62
|
-
const merge = ({union, equal}) => genericMerge({reduceOp: reduceOp(union)(equal), tailReduce: tailReduce(equal)})(
|
|
62
|
+
const merge = ({union, equal}) => genericMerge({reduceOp: reduceOp(union)(equal), tailReduce: tailReduce(equal)})(null)
|
|
63
63
|
|
|
64
64
|
/** @type {<T>(def: T) => (value: number) => (rm: RangeMapArray<T>) => T} */
|
|
65
65
|
const get = def => value => rm => {
|
|
@@ -18,14 +18,14 @@ module.exports = {
|
|
|
18
18
|
/** @type {_.RangeMap<sortedSet.SortedSet<string>>} */
|
|
19
19
|
const a = [[['a'], 1], [['b'], 2]]
|
|
20
20
|
/** @type {_.RangeMap<sortedSet.SortedSet<string>>} */
|
|
21
|
-
const b =
|
|
21
|
+
const b = null
|
|
22
22
|
const merged = _.merge(op)(a)(b)
|
|
23
23
|
const result = stringify(list.toArray(merged))
|
|
24
24
|
if (result !== '[[["a"],1],[["b"],2]]') { throw result }
|
|
25
25
|
},
|
|
26
26
|
() => {
|
|
27
27
|
/** @type {_.RangeMap<sortedSet.SortedSet<string>>} */
|
|
28
|
-
const a =
|
|
28
|
+
const a = null
|
|
29
29
|
/** @type {_.RangeMap<sortedSet.SortedSet<string>>} */
|
|
30
30
|
const b = [[['a'], 1], [['b'], 2]]
|
|
31
31
|
const merged = _.merge(op)(a)(b)
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
const compare = require('../function/compare/module.f.cjs')
|
|
2
2
|
const list = require('../list/module.f.cjs')
|
|
3
|
-
const option = require('../
|
|
3
|
+
const option = require('../nullable/module.f.cjs')
|
|
4
4
|
const { next } = list
|
|
5
5
|
const { identity } = require('../function/module.f.cjs')
|
|
6
|
-
const range = require('../range/module.f.cjs')
|
|
7
6
|
|
|
8
7
|
/**
|
|
9
8
|
* @template T
|
|
@@ -23,7 +22,7 @@ const range = require('../range/module.f.cjs')
|
|
|
23
22
|
/**
|
|
24
23
|
* @template T
|
|
25
24
|
* @template S
|
|
26
|
-
* @typedef {(state: S) => (a: T) => (b: T) => readonly[option.
|
|
25
|
+
* @typedef {(state: S) => (a: T) => (b: T) => readonly[option.Nullable<T>, compare.Sign, S]} ReduceOp
|
|
27
26
|
*/
|
|
28
27
|
|
|
29
28
|
/**
|
|
@@ -42,54 +41,53 @@ const range = require('../range/module.f.cjs')
|
|
|
42
41
|
*/
|
|
43
42
|
|
|
44
43
|
/** @type {<T,S>(reduce: MergeReduce<T,S>) => (state: S) => (a: list.List<T>) => (b: list.List<T>) => list.List<T>} */
|
|
45
|
-
const genericMerge =
|
|
46
|
-
|
|
47
|
-
/** @typedef {typeof reduce extends MergeReduce<infer T, infer S> ? [T, S] : never} TS */
|
|
44
|
+
const genericMerge = ({ reduceOp, tailReduce }) => {
|
|
45
|
+
/** @typedef {typeof reduceOp extends ReduceOp<infer T, infer S> ? [T, S] : never} TS */
|
|
48
46
|
/** @typedef {TS[0]} T */
|
|
49
47
|
/** @typedef {TS[1]} S */
|
|
50
48
|
/** @type {(state: S) => (a: list.List<T>) => (b: list.List<T>) => list.List<T>} */
|
|
51
49
|
const f = state => a => b => () => {
|
|
52
50
|
const aResult = next(a)
|
|
53
|
-
if (aResult ===
|
|
51
|
+
if (aResult === null) { return tailReduce(state)(b) }
|
|
54
52
|
const bResult = next(b)
|
|
55
|
-
if (bResult ===
|
|
53
|
+
if (bResult === null) { return tailReduce(state)(aResult) }
|
|
56
54
|
const [first, sign, stateNext] = reduceOp(state)(aResult.first)(bResult.first)
|
|
57
55
|
const aNext = sign === 1 ? a : aResult.tail
|
|
58
56
|
const bNext = sign === -1 ? b : bResult.tail
|
|
59
57
|
const tail = f(stateNext)(aNext)(bNext)
|
|
60
|
-
return first ===
|
|
58
|
+
return first === null ? tail : { first, tail }
|
|
61
59
|
}
|
|
62
60
|
return f
|
|
63
61
|
}
|
|
64
62
|
|
|
65
63
|
/**
|
|
66
64
|
* @template T
|
|
67
|
-
* @typedef {ReduceOp<T,
|
|
65
|
+
* @typedef {ReduceOp<T, null>} CmpReduceOp
|
|
68
66
|
*/
|
|
69
67
|
|
|
70
68
|
/** @type {<T>(cmp: Cmp<T>) => (a: SortedList<T>) => (b: SortedList<T>) => SortedList<T>} */
|
|
71
69
|
const merge = cmp => {
|
|
72
70
|
/** @typedef {typeof cmp extends Cmp<infer T> ? T : never} T*/
|
|
73
|
-
/** @type {TailReduce<T,
|
|
71
|
+
/** @type {TailReduce<T, null>} */
|
|
74
72
|
const tailReduce = mergeTail
|
|
75
|
-
return genericMerge({ reduceOp: cmpReduce(cmp), tailReduce })(
|
|
73
|
+
return genericMerge({ reduceOp: cmpReduce(cmp), tailReduce })(null)
|
|
76
74
|
}
|
|
77
75
|
|
|
78
76
|
/** @type {<T>(cmp: Cmp<T>) => CmpReduceOp<T>} */
|
|
79
77
|
const cmpReduce = cmp => () => a => b => {
|
|
80
78
|
const sign = cmp(a)(b)
|
|
81
|
-
return [sign === 1 ? b : a, sign,
|
|
79
|
+
return [sign === 1 ? b : a, sign, null]
|
|
82
80
|
}
|
|
83
81
|
|
|
84
82
|
/** @type {() => <T>(tail: list.List<T>) => list.List<T>} */
|
|
85
83
|
const mergeTail = () => identity
|
|
86
84
|
|
|
87
|
-
/** @type {<T>(cmp: Cmp<T>) => (value: T) => (array: SortedArray<T>) => T|
|
|
85
|
+
/** @type {<T>(cmp: Cmp<T>) => (value: T) => (array: SortedArray<T>) => T|null} */
|
|
88
86
|
const find = cmp => value => array => {
|
|
89
87
|
let b = 0
|
|
90
88
|
let e = array.length - 1
|
|
91
89
|
while (true) {
|
|
92
|
-
if (e - b < 0) return
|
|
90
|
+
if (e - b < 0) return null
|
|
93
91
|
const mid = b + (e - b >> 1)
|
|
94
92
|
const sign = cmp(value)(array[mid])
|
|
95
93
|
switch(sign) {
|