functionalscript 0.0.168 → 0.0.178
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/btree/index.js +52 -19
- package/btree/test.js +33 -0
- package/cmp/index.js +9 -4
- package/function/index.js +0 -17
- package/function/operator/index.js +18 -0
- package/map/index.js +5 -4
- package/module-manager/index.js +9 -10
- package/option/index.js +7 -2
- package/package.json +1 -1
- package/sequence/README.md +53 -0
- package/{array → sequence/array}/index.js +11 -1
- package/sequence/asyncIterable/index.js +111 -0
- package/{async/iterable → sequence/asyncIterable}/test.js +2 -2
- package/sequence/index.js +27 -68
- package/sequence/iterable/index.js +109 -0
- package/{iterable → sequence/iterable}/test.js +1 -1
- package/sequence/list/index.js +194 -0
- package/sequence/list/test.js +36 -0
- package/test.js +4 -2
- package/async/iterable/index.js +0 -133
- package/iterable/index.js +0 -116
package/btree/index.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
const { index3, index5 } = require('../cmp')
|
|
2
|
+
const list = require('../sequence/list')
|
|
3
|
+
const { pipe } = require('../function')
|
|
2
4
|
|
|
3
5
|
/**
|
|
4
6
|
* @template T
|
|
@@ -12,24 +14,24 @@ const { index3, index5 } = require('../cmp')
|
|
|
12
14
|
|
|
13
15
|
/**
|
|
14
16
|
* @template T
|
|
15
|
-
* @typedef {import('../array').Array1<T>} Array1
|
|
17
|
+
* @typedef {import('../sequence/array').Array1<T>} Array1
|
|
16
18
|
*/
|
|
17
19
|
|
|
18
20
|
/**
|
|
19
21
|
* @template T
|
|
20
|
-
* @typedef {import('../array').Array2<T>} Array2
|
|
22
|
+
* @typedef {import('../sequence/array').Array2<T>} Array2
|
|
21
23
|
*/
|
|
22
24
|
|
|
23
25
|
/**
|
|
24
26
|
* @template T
|
|
25
|
-
* @typedef {import('../array').Array3<T>} Array3
|
|
27
|
+
* @typedef {import('../sequence/array').Array3<T>} Array3
|
|
26
28
|
*/
|
|
27
29
|
|
|
28
|
-
/** @typedef {import('../array').Index2} Index2 */
|
|
30
|
+
/** @typedef {import('../sequence/array').Index2} Index2 */
|
|
29
31
|
|
|
30
|
-
/** @typedef {import('../array').Index3} Index3 */
|
|
32
|
+
/** @typedef {import('../sequence/array').Index3} Index3 */
|
|
31
33
|
|
|
32
|
-
/** @typedef {import('../array').Index5} Index5 */
|
|
34
|
+
/** @typedef {import('../sequence/array').Index5} Index5 */
|
|
33
35
|
|
|
34
36
|
//
|
|
35
37
|
|
|
@@ -45,17 +47,17 @@ const { index3, index5 } = require('../cmp')
|
|
|
45
47
|
|
|
46
48
|
/**
|
|
47
49
|
* @template T
|
|
48
|
-
* @typedef {readonly [
|
|
50
|
+
* @typedef {readonly [Node<T>, T, Node<T>]} Branch3
|
|
49
51
|
*/
|
|
50
52
|
|
|
51
53
|
/**
|
|
52
54
|
* @template T
|
|
53
|
-
* @typedef {readonly [
|
|
55
|
+
* @typedef {readonly [Node<T>, T, Node<T>, T, Node<T>]} Branch5
|
|
54
56
|
*/
|
|
55
57
|
|
|
56
58
|
/**
|
|
57
59
|
* @template T
|
|
58
|
-
* @typedef { Leaf1<T> | Leaf2<T> | Branch3<T> | Branch5<T>}
|
|
60
|
+
* @typedef { Leaf1<T> | Leaf2<T> | Branch3<T> | Branch5<T>} Node
|
|
59
61
|
*/
|
|
60
62
|
|
|
61
63
|
/** @typedef {{ readonly done: false }} NotFoundDone */
|
|
@@ -75,7 +77,7 @@ const { index3, index5 } = require('../cmp')
|
|
|
75
77
|
|
|
76
78
|
/**
|
|
77
79
|
* @template T
|
|
78
|
-
* @typedef {{ readonly replace:
|
|
80
|
+
* @typedef {{ readonly replace: Node<T> }} Replace
|
|
79
81
|
*/
|
|
80
82
|
|
|
81
83
|
/**
|
|
@@ -123,7 +125,7 @@ const { index3, index5 } = require('../cmp')
|
|
|
123
125
|
|
|
124
126
|
/**
|
|
125
127
|
* @template T
|
|
126
|
-
* @typedef { readonly [
|
|
128
|
+
* @typedef { readonly [Node<T>, T, Node<T>, T, Node<T>, T, Node<T>] } Branch7
|
|
127
129
|
*/
|
|
128
130
|
|
|
129
131
|
/** @type {<T>(n: Branch7<T>) => Branch3<T>} */
|
|
@@ -131,7 +133,7 @@ const split = ([n0, v1, n2, v3, n4, v5, n6]) => [[n0, v1, n2], v3, [n4, v5, n6]]
|
|
|
131
133
|
|
|
132
134
|
/**
|
|
133
135
|
* @type {<T>(overflow: (o: Branch3<T>) => Result<T>) =>
|
|
134
|
-
* (replace: (r:
|
|
136
|
+
* (replace: (r: Node<T>) => Node<T>) =>
|
|
135
137
|
* (result: Result<T>) =>
|
|
136
138
|
* Result<T>}
|
|
137
139
|
*/
|
|
@@ -143,7 +145,7 @@ const merge = overflow => replace => result => {
|
|
|
143
145
|
|
|
144
146
|
/**
|
|
145
147
|
* @type {<T>(overflow: (o: Branch3<T>) => Branch5<T>) =>
|
|
146
|
-
* (replace: (r:
|
|
148
|
+
* (replace: (r: Node<T>) => Branch3<T>) =>
|
|
147
149
|
* (result: Result<T>) =>
|
|
148
150
|
* Result<T>}
|
|
149
151
|
*/
|
|
@@ -151,19 +153,19 @@ const merge2 = overflow => merge(o => ({ replace: overflow(o) }))
|
|
|
151
153
|
|
|
152
154
|
/**
|
|
153
155
|
* @type {<T>(overflow: (o: Branch3<T>) => Branch7<T>) =>
|
|
154
|
-
* (replace: (r:
|
|
156
|
+
* (replace: (r: Node<T>) => Branch5<T>) =>
|
|
155
157
|
* (result: Result<T>) =>
|
|
156
158
|
* Result<T>}
|
|
157
159
|
*/
|
|
158
160
|
const merge3 = overflow => merge(o => ({ overflow: split(overflow(o)) }))
|
|
159
161
|
|
|
160
|
-
/** @type {(visitor: Visitor) => <T>(cmp: Cmp<T>) => (init: Lazy<T>) => (node:
|
|
162
|
+
/** @type {(visitor: Visitor) => <T>(cmp: Cmp<T>) => (init: Lazy<T>) => (node: Node<T>) => Result<T>} */
|
|
161
163
|
const visit = ({ found, notFound }) => cmp => {
|
|
162
164
|
const i3 = index3(cmp)
|
|
163
165
|
const i5 = index5(cmp)
|
|
164
166
|
return init => {
|
|
165
167
|
/** @typedef {typeof cmp extends Cmp<infer T> ? T : never} T*/
|
|
166
|
-
/** @type {(node:
|
|
168
|
+
/** @type {(node: Node<T>) => Result<T>} */
|
|
167
169
|
const f = node => {
|
|
168
170
|
switch (node.length) {
|
|
169
171
|
case 1: {
|
|
@@ -255,7 +257,7 @@ const notFoundGet = {
|
|
|
255
257
|
leaf2_right: notFound,
|
|
256
258
|
}
|
|
257
259
|
|
|
258
|
-
/** @type { <T>(_:
|
|
260
|
+
/** @type { <T>(_: Node<T>) => Replace<T> } */
|
|
259
261
|
const replace = node => ({ replace: node })
|
|
260
262
|
|
|
261
263
|
/** @type {Found} */
|
|
@@ -304,7 +306,7 @@ const replaceVisitor = {
|
|
|
304
306
|
notFound: notFoundGet,
|
|
305
307
|
}
|
|
306
308
|
|
|
307
|
-
/** @type {<T>(_:
|
|
309
|
+
/** @type {<T>(_: Node<T>) => Iterable<T>} */
|
|
308
310
|
const values = node => ({
|
|
309
311
|
*[Symbol.iterator]() {
|
|
310
312
|
switch (node.length) {
|
|
@@ -330,12 +332,43 @@ const values = node => ({
|
|
|
330
332
|
}
|
|
331
333
|
})
|
|
332
334
|
|
|
335
|
+
/** @type {<T>(...array: readonly list.List<T>[]) => list.List<T>} */
|
|
336
|
+
const flatArray = (...array) => list.flat(list.fromArray(array))
|
|
337
|
+
|
|
338
|
+
/** @type {<T>(node: Node<T>) => list.List<T>} */
|
|
339
|
+
const valuesList = node => () => {
|
|
340
|
+
const f = () => {
|
|
341
|
+
switch (node.length) {
|
|
342
|
+
case 1: case 2: { return list.fromArray(node) }
|
|
343
|
+
case 3: {
|
|
344
|
+
return flatArray(
|
|
345
|
+
valuesList(node[0]),
|
|
346
|
+
list.one(node[1]),
|
|
347
|
+
valuesList(node[2])
|
|
348
|
+
)
|
|
349
|
+
}
|
|
350
|
+
default: {
|
|
351
|
+
return flatArray(
|
|
352
|
+
valuesList(node[0]),
|
|
353
|
+
list.one(node[1]),
|
|
354
|
+
valuesList(node[2]),
|
|
355
|
+
list.one(node[3]),
|
|
356
|
+
valuesList(node[4])
|
|
357
|
+
)
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
return f()()
|
|
362
|
+
}
|
|
363
|
+
|
|
333
364
|
module.exports = {
|
|
365
|
+
/** @readonly */
|
|
366
|
+
valuesList,
|
|
334
367
|
/** @readonly */
|
|
335
368
|
values,
|
|
336
369
|
/**
|
|
337
370
|
* @readonly
|
|
338
|
-
* @type { <T>(cmp: Cmp<T>) => (node:
|
|
371
|
+
* @type { <T>(cmp: Cmp<T>) => (node: Node<T>) => T|undefined }
|
|
339
372
|
*/
|
|
340
373
|
getVisitor: cmp => node => {
|
|
341
374
|
const result = visit(getVisitor)(cmp)(() => { throw '' })(node)
|
package/btree/test.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const btree = require('.')
|
|
2
|
+
const { setVisitor, valuesList } = btree
|
|
3
|
+
const { cmp } = require('../cmp')
|
|
4
|
+
|
|
5
|
+
/** @type {(node: btree.Node<string>) => (value: string) => btree.Node<string>} */
|
|
6
|
+
const set = node => value => {
|
|
7
|
+
const result = setVisitor(cmp(value))(() => value)(node)
|
|
8
|
+
if ('replace' in result) { return result.replace }
|
|
9
|
+
if ('overflow' in result) { return result.overflow }
|
|
10
|
+
return node
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const test = () => {
|
|
14
|
+
/** @type {btree.Node<string>} */
|
|
15
|
+
let node = ['a']
|
|
16
|
+
node = set(node)('b')
|
|
17
|
+
node = set(node)('c')
|
|
18
|
+
node = set(node)('d')
|
|
19
|
+
node = set(node)('e')
|
|
20
|
+
node = set(node)('f')
|
|
21
|
+
//
|
|
22
|
+
{
|
|
23
|
+
/** @type {import('../sequence/list').Result<string>} */
|
|
24
|
+
let result = valuesList(node)()
|
|
25
|
+
while (result !== undefined) {
|
|
26
|
+
const t = result[0]
|
|
27
|
+
console.log(t)
|
|
28
|
+
result = result[1]()
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
test()
|
package/cmp/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
/** @typedef {import('../array').Index3} Index3 */
|
|
2
|
-
/** @typedef {import('../array').Index5} Index5 */
|
|
1
|
+
/** @typedef {import('../sequence/array').Index3} Index3 */
|
|
2
|
+
/** @typedef {import('../sequence/array').Index5} Index5 */
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* @template T
|
|
6
|
-
* @typedef {import('../array').Array2<T>} Array2
|
|
6
|
+
* @typedef {import('../sequence/array').Array2<T>} Array2
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
/** @typedef {-1|0|1} Sign */
|
|
@@ -22,9 +22,14 @@ const index5 = cmp => ([v0, v1]) => {
|
|
|
22
22
|
return /** @type {Index5} */ (i <= 0 ? i + 1 : cmp(v1) + 3)
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
/** @type {(a: string) => (b: string) => Sign} */
|
|
26
|
+
const cmp = a => b => a < b ? -1 : a === b ? 0 : 1
|
|
27
|
+
|
|
25
28
|
module.exports = {
|
|
26
29
|
/** @readonly */
|
|
27
30
|
index3,
|
|
28
31
|
/** @readonly */
|
|
29
32
|
index5,
|
|
30
|
-
|
|
33
|
+
/** @readonly */
|
|
34
|
+
cmp,
|
|
35
|
+
}
|
package/function/index.js
CHANGED
|
@@ -13,21 +13,6 @@ const pipe = g => f => x => f(g(x))
|
|
|
13
13
|
/** @type {<T>(value: T) => T} */
|
|
14
14
|
const id = value => value
|
|
15
15
|
|
|
16
|
-
/**
|
|
17
|
-
* @template I
|
|
18
|
-
* @template O
|
|
19
|
-
* @typedef {{
|
|
20
|
-
* readonly pipe: <R>(f: Func<O, R>) => Pipe<I, R>
|
|
21
|
-
* readonly call: Func<I, O>
|
|
22
|
-
* }} Pipe
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
/** @type {<I, O>(f: Func<I, O>) => Pipe<I, O>} */
|
|
26
|
-
const pipex = call => ({
|
|
27
|
-
pipe: f => pipex(pipe(call)(f)),
|
|
28
|
-
call,
|
|
29
|
-
})
|
|
30
|
-
|
|
31
16
|
module.exports = {
|
|
32
17
|
/** @readonly */
|
|
33
18
|
id,
|
|
@@ -35,6 +20,4 @@ module.exports = {
|
|
|
35
20
|
pipe,
|
|
36
21
|
/** @readonly */
|
|
37
22
|
combine,
|
|
38
|
-
/** @readonly */
|
|
39
|
-
pipex,
|
|
40
23
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @template R
|
|
3
|
+
* @template T
|
|
4
|
+
* @typedef {(prior: R) => (value: T) => R} BinaryOperator
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/** @type {(separator: string) => BinaryOperator<string, string>} */
|
|
8
|
+
const join = separator => prior => value => `${prior}${separator}${value}`
|
|
9
|
+
|
|
10
|
+
/** @type {(sum: number) => (value: number) => number} */
|
|
11
|
+
const addition = a => b => a + b
|
|
12
|
+
|
|
13
|
+
module.exports = {
|
|
14
|
+
/** @readonly */
|
|
15
|
+
join,
|
|
16
|
+
/** @readonly */
|
|
17
|
+
addition,
|
|
18
|
+
}
|
package/map/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const option = require("../option")
|
|
2
2
|
const { getVisitor, setVisitor, values } = require("../btree")
|
|
3
|
+
const { cmp } = require("../cmp")
|
|
3
4
|
|
|
4
5
|
/** @typedef {import("../cmp").Sign} Sign */
|
|
5
6
|
|
|
@@ -10,7 +11,7 @@ const { getVisitor, setVisitor, values } = require("../btree")
|
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* @template T
|
|
13
|
-
* @typedef {import("../btree").
|
|
14
|
+
* @typedef {import("../btree").Node<T>} TNode
|
|
14
15
|
*/
|
|
15
16
|
|
|
16
17
|
/**
|
|
@@ -34,13 +35,13 @@ const { getVisitor, setVisitor, values } = require("../btree")
|
|
|
34
35
|
*/
|
|
35
36
|
|
|
36
37
|
/** @type {(a: string) => <T>(b: Entry<T>) => Sign} */
|
|
37
|
-
const
|
|
38
|
+
const keyCmp = a => ([b]) => cmp(a)(b)
|
|
38
39
|
|
|
39
40
|
/** @type {<T>(node: TNode<Entry<T>>) => Map<T>} */
|
|
40
41
|
const create = root => ({
|
|
41
|
-
get: name => option.map(([,value]) => value)(getVisitor(
|
|
42
|
+
get: name => option.map(([,value]) => value)(getVisitor(keyCmp(name))(root)),
|
|
42
43
|
set: name => value => {
|
|
43
|
-
const result = setVisitor(
|
|
44
|
+
const result = setVisitor(keyCmp(name))(() => [name, value])(root)
|
|
44
45
|
if ('replace' in result) { return create(result.replace) }
|
|
45
46
|
if ('overflow' in result) { return create(result.overflow) }
|
|
46
47
|
throw ''
|
package/module-manager/index.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
const array = require('../array')
|
|
1
|
+
const array = require('../sequence/array')
|
|
2
2
|
const { pipe } = require('../function')
|
|
3
3
|
const option = require('../option')
|
|
4
4
|
const { head, last, splitLast, splitFirst } = array
|
|
5
|
-
const iter = require('../iterable')
|
|
5
|
+
const iter = require('../sequence/iterable')
|
|
6
|
+
const seq = require('../sequence')
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* @template T
|
|
@@ -38,24 +39,22 @@ const iter = require('../iterable')
|
|
|
38
39
|
|
|
39
40
|
/** @typedef {(_: string) => undefined|Package|Dependencies} Dependencies */
|
|
40
41
|
|
|
41
|
-
/** @type {
|
|
42
|
-
const pathNormReduce =
|
|
43
|
-
|
|
42
|
+
/** @type {seq.InclusiveScan<string, undefined|Path>} */
|
|
43
|
+
const pathNormReduce = seq.inclusiveScan
|
|
44
|
+
(path => item =>
|
|
44
45
|
path === undefined ?
|
|
45
46
|
undefined :
|
|
46
47
|
['', '.'].includes(item) ?
|
|
47
48
|
path :
|
|
48
49
|
item === '..' ?
|
|
49
50
|
head(path) :
|
|
50
|
-
[...path, item]
|
|
51
|
-
|
|
52
|
-
result: s => s,
|
|
53
|
-
}
|
|
51
|
+
[...path, item])
|
|
52
|
+
([])
|
|
54
53
|
|
|
55
54
|
/** @type {(_: Array<string>) => boolean} */
|
|
56
55
|
const isRelative = localId => ['.', '..'].includes(localId[0])
|
|
57
56
|
|
|
58
|
-
const pathNorm = iter.
|
|
57
|
+
const pathNorm = iter.reduce(pathNormReduce)
|
|
59
58
|
|
|
60
59
|
/** @type {(_: Package) => (_: Path) => Module|undefined} */
|
|
61
60
|
const internal = pack => {
|
package/option/index.js
CHANGED
|
@@ -3,10 +3,15 @@
|
|
|
3
3
|
* @typedef {T|undefined} Option
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
/** @type {<T, R>(
|
|
7
|
-
const map = f =>
|
|
6
|
+
/** @type {<T, R>(f: (value: T) => R) => (value: T|undefined) => R|undefined} */
|
|
7
|
+
const map = f => value => value === undefined ? undefined : f(value)
|
|
8
|
+
|
|
9
|
+
/** @type {<T, R>(f: (_: T) => R) => (none: () => R) => (_: T|undefined) => R|undefined} */
|
|
10
|
+
const match = f => none => value => value === undefined ? none() : f(value)
|
|
8
11
|
|
|
9
12
|
module.exports = {
|
|
10
13
|
/** @readonly */
|
|
11
14
|
map,
|
|
15
|
+
/** @readonly */
|
|
16
|
+
match,
|
|
12
17
|
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Sequences
|
|
2
|
+
|
|
3
|
+
Sequence types:
|
|
4
|
+
|
|
5
|
+
- Array
|
|
6
|
+
- List
|
|
7
|
+
- Iterable
|
|
8
|
+
- AsyncIterable
|
|
9
|
+
|
|
10
|
+
## Functions
|
|
11
|
+
|
|
12
|
+
See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array
|
|
13
|
+
|
|
14
|
+
- `length: Sequence<infer T> => number`
|
|
15
|
+
- `at: number => Sequence<infer T> = T`
|
|
16
|
+
- `concat: Sequence<infer T> => Sequence<T> => Sequence<T>`
|
|
17
|
+
- `entries: Sequence<infer T> => Sequence<[number, T]>`
|
|
18
|
+
- `every: (infer T => boolean) => Sequence<T> => boolean`
|
|
19
|
+
- `filter: (infer T => boolean) => Sequence<T> => Sequence<T>`
|
|
20
|
+
- `find: (infer T => boolean) => Sequence<T> => T`
|
|
21
|
+
- `findIndex: (infer T => boolean) => Sequence<T> => number`
|
|
22
|
+
- `flat: Sequence<Sequence<T>> => Sequence<T>`
|
|
23
|
+
- `flatMap: (infer T => Sequence<infer R>) => Sequence<T> => Sequence<R>`
|
|
24
|
+
- `includes: infer T => Sequence<T> => boolean`
|
|
25
|
+
- `indexOf: infer T => Sequence<T> => number`
|
|
26
|
+
- `join: string => Sequence<string> => string`
|
|
27
|
+
- `keys: Sequence<T> => Sequence<string>`
|
|
28
|
+
- `lastIndexOf: infer T => Sequence<T> => number`
|
|
29
|
+
- `map: (infer T => infer R) => Sequence<T> => Sequence<R>`
|
|
30
|
+
- `reduce: ...Scan<T, R> => Sequence<T> => R`
|
|
31
|
+
- `some: (infer T => boolean) => Sequence<T> => boolean`
|
|
32
|
+
|
|
33
|
+
### Priority 2.
|
|
34
|
+
|
|
35
|
+
- `slice: number => number => Sequence<T> => Sequence<T>`
|
|
36
|
+
- `reduceRight: ...Scan<T, R> => Sequence<T> => R`
|
|
37
|
+
- `toLocalString: Locales => Sequence<T> => string`
|
|
38
|
+
|
|
39
|
+
### Priority 3.
|
|
40
|
+
|
|
41
|
+
- `values: Sequence<infer T> => Sequence<T>`
|
|
42
|
+
|
|
43
|
+
## Prohibited Array Operations
|
|
44
|
+
|
|
45
|
+
- `copyWithin`
|
|
46
|
+
- `fill`
|
|
47
|
+
- `pop`
|
|
48
|
+
- `push`
|
|
49
|
+
- `reverse`
|
|
50
|
+
- `shift`
|
|
51
|
+
- `sort`
|
|
52
|
+
- `splice`
|
|
53
|
+
- `unshift`
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const option = require('
|
|
1
|
+
const option = require('../../option')
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* @template T
|
|
@@ -44,6 +44,11 @@ const option = require('../option')
|
|
|
44
44
|
* @typedef {readonly [T, T, T, T, T]} Array5
|
|
45
45
|
*/
|
|
46
46
|
|
|
47
|
+
/**
|
|
48
|
+
* @template T
|
|
49
|
+
* @typedef {Array1<T>| Array2<T> | Array3<T> | Array4<T> | Array5<T>} Array1_5
|
|
50
|
+
*/
|
|
51
|
+
|
|
47
52
|
/** @typedef {0|1|2|3|4} Index5 */
|
|
48
53
|
|
|
49
54
|
/** @type {<T>(_: Array<T>) => Array<T>} */
|
|
@@ -80,7 +85,12 @@ const splitLast = a => {
|
|
|
80
85
|
return option.map(split)(last(a))
|
|
81
86
|
}
|
|
82
87
|
|
|
88
|
+
/** @type {(index: number) => <T>(a: Array<T>) => readonly[T]|undefined} */
|
|
89
|
+
const at = index => a => index < a.length ? [a[index]] : undefined
|
|
90
|
+
|
|
83
91
|
module.exports = {
|
|
92
|
+
/** @readonly */
|
|
93
|
+
at,
|
|
84
94
|
/** @readnly */
|
|
85
95
|
first,
|
|
86
96
|
/** @readonly */
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
const { pipe } = require('../../function')
|
|
2
|
+
const seq = require('..')
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @template T
|
|
6
|
+
* @typedef {Promise<T>|T} PromiseOrValue
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @template T
|
|
11
|
+
* @typedef {Iterable<T> | AsyncIterable<T>} AsyncOrSyncIterable
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/** @type {<T>(c: AsyncOrSyncIterable<AsyncOrSyncIterable<T>>) => AsyncIterable<T>} */
|
|
15
|
+
const flat = c => ({
|
|
16
|
+
async *[Symbol.asyncIterator]() {
|
|
17
|
+
for await (const i of c) {
|
|
18
|
+
yield* i
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
/** @type {<T, R>(f: (value: T) => AsyncOrSyncIterable<R>) => (c: AsyncOrSyncIterable<T>) => AsyncIterable<R>} */
|
|
24
|
+
const flatMap = f => c => ({
|
|
25
|
+
async *[Symbol.asyncIterator]() {
|
|
26
|
+
for await (const i of c) {
|
|
27
|
+
yield* await f(i)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
/** @type {<T, R>(f: (value: T) => R) => (c: AsyncOrSyncIterable<T>) => AsyncIterable<R>} */
|
|
33
|
+
const map = seq.map(flatMap)
|
|
34
|
+
|
|
35
|
+
/** @type {<T>(f: (value: T) => boolean) => (c: AsyncOrSyncIterable<T>) => AsyncOrSyncIterable<T>} */
|
|
36
|
+
const filter = seq.filter(flatMap)
|
|
37
|
+
|
|
38
|
+
/** @type {<T>(a: AsyncOrSyncIterable<T>) => (b: AsyncOrSyncIterable<T>) => AsyncIterable<T>} */
|
|
39
|
+
const concat = a => b => ({
|
|
40
|
+
async *[Symbol.asyncIterator]() {
|
|
41
|
+
yield* a
|
|
42
|
+
yield* b
|
|
43
|
+
}
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
/** @type {<T, R>(s: seq.Scan<T, R>) => (c: AsyncOrSyncIterable<T>) => AsyncIterable<R>} */
|
|
47
|
+
const scan = s => c => ({
|
|
48
|
+
async *[Symbol.asyncIterator]() {
|
|
49
|
+
let next = s
|
|
50
|
+
for await (const i of c) {
|
|
51
|
+
const result = next(i)
|
|
52
|
+
next = result[1]
|
|
53
|
+
yield result[0]
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
/** @type {<T, R>(s: seq.InclusiveScan<T, R>) => (c: AsyncOrSyncIterable<T>) => AsyncIterable<R>} */
|
|
59
|
+
const inclusiveScan = ([first, s]) => c => concat([first])(scan(s)(c))
|
|
60
|
+
|
|
61
|
+
/** @type {<T, R>(is: seq.InclusiveScan<T, R>) => (c: AsyncOrSyncIterable<T>) => Promise<R>} */
|
|
62
|
+
const reduce = ([first, s]) => async c => {
|
|
63
|
+
let next = first
|
|
64
|
+
for await (const i of scan(s)(c)) {
|
|
65
|
+
next = i
|
|
66
|
+
}
|
|
67
|
+
return next
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const sum = reduce(seq.sum)
|
|
71
|
+
|
|
72
|
+
const join = pipe(seq.join)(reduce)
|
|
73
|
+
|
|
74
|
+
const length = reduce(seq.length)
|
|
75
|
+
|
|
76
|
+
/** @type {<T>(f: (value: T) => boolean) => (c: AsyncOrSyncIterable<T>) => AsyncIterable<T>} */
|
|
77
|
+
const takeWhile = f => c => ({
|
|
78
|
+
async *[Symbol.asyncIterator]() {
|
|
79
|
+
for await (const i of c) {
|
|
80
|
+
if (!f(i)) { return }
|
|
81
|
+
yield i
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
module.exports = {
|
|
87
|
+
/** @readonly */
|
|
88
|
+
concat,
|
|
89
|
+
/** @readonly */
|
|
90
|
+
flat,
|
|
91
|
+
/** @readonly */
|
|
92
|
+
map,
|
|
93
|
+
/** @readonly */
|
|
94
|
+
filter,
|
|
95
|
+
/** @readonly */
|
|
96
|
+
flatMap,
|
|
97
|
+
/** @readonly */
|
|
98
|
+
reduce,
|
|
99
|
+
/** @readonly */
|
|
100
|
+
sum,
|
|
101
|
+
/** @readonly */
|
|
102
|
+
length,
|
|
103
|
+
/** @readonly */
|
|
104
|
+
join,
|
|
105
|
+
/** @readonly */
|
|
106
|
+
scan,
|
|
107
|
+
/** @readonly */
|
|
108
|
+
inclusiveScan,
|
|
109
|
+
/** @readonly */
|
|
110
|
+
takeWhile,
|
|
111
|
+
}
|
|
@@ -3,13 +3,13 @@ const { map, filter, flatMap, sum } = require('.')
|
|
|
3
3
|
const test = async () => {
|
|
4
4
|
{
|
|
5
5
|
const a = [1, 2, 3]
|
|
6
|
-
const m = map(
|
|
6
|
+
const m = map(x => x * x)(a)
|
|
7
7
|
const result = await sum(m)
|
|
8
8
|
if (result !== 14) { throw 'filter' }
|
|
9
9
|
}
|
|
10
10
|
{
|
|
11
11
|
const a = [1, 2, 3, 4]
|
|
12
|
-
const f = filter(
|
|
12
|
+
const f = filter(x => x !== 2)(a)
|
|
13
13
|
const result = await sum(f)
|
|
14
14
|
if (result !== 8) { throw 'filter' }
|
|
15
15
|
}
|
package/sequence/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
const
|
|
1
|
+
const op = require('../function/operator')
|
|
2
2
|
const { id } = require('../function')
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* @template T0
|
|
6
6
|
* @template T1
|
|
7
|
-
* @typedef {import('
|
|
7
|
+
* @typedef {import('./array').Tuple2<T0, T1>} Tuple2
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
/**
|
|
@@ -22,21 +22,12 @@ const { id } = require('../function')
|
|
|
22
22
|
/**
|
|
23
23
|
* @template T
|
|
24
24
|
* @template R
|
|
25
|
-
* @typedef {
|
|
26
|
-
* readonly scan: Scan<T, R>
|
|
27
|
-
* readonly first: R
|
|
28
|
-
* }} InclusiveScan
|
|
25
|
+
* @typedef {Tuple2<R, Scan<T, R>>} InclusiveScan
|
|
29
26
|
*/
|
|
30
27
|
|
|
31
|
-
/**
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
* @typedef {(prior: R) => (value: T) => R} BinaryOperator
|
|
35
|
-
*/
|
|
36
|
-
|
|
37
|
-
/** @type {<R, T>(operator: BinaryOperator<R, T>) => (prior: R) => Scan<T, R>} */
|
|
38
|
-
const operatorScan = operator => {
|
|
39
|
-
/** @typedef {typeof operator extends BinaryOperator<infer R, infer T> ? [R, T] : never} RT */
|
|
28
|
+
/** @type {<R, T>(operator: op.BinaryOperator<R, T>) => (prior: R) => Scan<T, R>} */
|
|
29
|
+
const scan = operator => {
|
|
30
|
+
/** @typedef {typeof operator extends op.BinaryOperator<infer R, infer T> ? [R, T] : never} RT */
|
|
40
31
|
/** @typedef {RT[0]} R */
|
|
41
32
|
/** @typedef {RT[1]} T */
|
|
42
33
|
/** @type {(prior: R) => Scan<T, R>} */
|
|
@@ -47,11 +38,8 @@ const operatorScan = operator => {
|
|
|
47
38
|
return f
|
|
48
39
|
}
|
|
49
40
|
|
|
50
|
-
/** @type {<R, T>(operator: BinaryOperator<R, T>) => (first: R) => InclusiveScan<T, R>} */
|
|
51
|
-
const
|
|
52
|
-
scan: operatorScan(operator)(first),
|
|
53
|
-
first,
|
|
54
|
-
})
|
|
41
|
+
/** @type {<R, T>(operator: op.BinaryOperator<R, T>) => (first: R) => InclusiveScan<T, R>} */
|
|
42
|
+
const inclusiveScan = operator => first => [first, scan(operator)(first)]
|
|
55
43
|
|
|
56
44
|
/**
|
|
57
45
|
* @template T
|
|
@@ -63,69 +51,40 @@ const createEntries = index => value => [[index, value], createEntries(index + 1
|
|
|
63
51
|
|
|
64
52
|
const entries = createEntries(0)
|
|
65
53
|
|
|
66
|
-
/** @type {(separator: string) => BinaryOperator<string, string>} */
|
|
67
|
-
const joinOperation = separator => prior => value => `${prior}${separator}${value}`
|
|
68
|
-
|
|
69
54
|
/** @type {(separator: string) => InclusiveScan<string, string>} */
|
|
70
|
-
const
|
|
71
|
-
scan: value => [value, operatorScan(joinOperation(separator))(value)],
|
|
72
|
-
first: ''
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
/** @type {(sum: number) => (value: number) => number} */
|
|
76
|
-
const addition = a => b => a + b
|
|
55
|
+
const join = separator => ['', value => [value, scan(op.join(separator))(value)]]
|
|
77
56
|
|
|
78
|
-
|
|
79
|
-
const sum2 = inclusiveOperatorScan(addition)(0)
|
|
57
|
+
const sum = inclusiveScan(op.addition)(0)
|
|
80
58
|
|
|
81
|
-
|
|
59
|
+
const length = inclusiveScan(a => () => a + 1)(0)
|
|
82
60
|
|
|
83
61
|
/**
|
|
84
|
-
* @template
|
|
85
|
-
* @template
|
|
86
|
-
* @
|
|
87
|
-
* @typedef {{
|
|
88
|
-
* readonly merge: BinaryOperator<S, I>
|
|
89
|
-
* readonly result: (state: S) => O
|
|
90
|
-
* readonly init: S
|
|
91
|
-
* }} Operation
|
|
62
|
+
* @template T
|
|
63
|
+
* @template R
|
|
64
|
+
* @typedef {(value: T) => R} Func
|
|
92
65
|
*/
|
|
93
66
|
|
|
94
|
-
/** @type {(
|
|
95
|
-
const
|
|
96
|
-
merge: s => i => s === undefined ? i : `${s}${separator}${i}`,
|
|
97
|
-
init: undefined,
|
|
98
|
-
result: s => s === undefined ? '' : s
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
/** @type {Operation<number, number, number>} */
|
|
102
|
-
const sum = {
|
|
103
|
-
merge: a => i => a + i,
|
|
104
|
-
result: id,
|
|
105
|
-
init: 0,
|
|
106
|
-
}
|
|
67
|
+
/** @type {<T, R, X>(flatMap: (f: Func<T, readonly[R]>) => X) => (f: Func<T, R>) =>X} */
|
|
68
|
+
const map = flatMap => f => flatMap(x => [f(x)])
|
|
107
69
|
|
|
108
|
-
/**
|
|
109
|
-
|
|
110
|
-
* readonly merge: (counter: number) => () => number
|
|
111
|
-
* readonly result: (counter: number) => number
|
|
112
|
-
* readonly init: number
|
|
113
|
-
* }}
|
|
114
|
-
*/
|
|
115
|
-
const size = {
|
|
116
|
-
merge: counter => () => counter + 1,
|
|
117
|
-
init: 0,
|
|
118
|
-
result: id,
|
|
119
|
-
}
|
|
70
|
+
/** @type {<T, X>(flatMap: (f: Func<T, readonly[T]|[]>) => X) => (f: Func<T, boolean>) =>X} */
|
|
71
|
+
const filter = flatMap => f => flatMap(x => f(x) ? [x] : [])
|
|
120
72
|
|
|
121
73
|
module.exports = {
|
|
74
|
+
/** @readonly */
|
|
75
|
+
inclusiveScan,
|
|
76
|
+
/** @readonly */
|
|
77
|
+
scan,
|
|
122
78
|
/** @readonly */
|
|
123
79
|
join,
|
|
124
|
-
join2,
|
|
125
80
|
/** @readonly */
|
|
126
81
|
sum,
|
|
127
82
|
/** @readonly */
|
|
128
|
-
|
|
83
|
+
length,
|
|
129
84
|
/** @readonly */
|
|
130
85
|
entries,
|
|
86
|
+
/** @readonly */
|
|
87
|
+
map,
|
|
88
|
+
/** @readonly */
|
|
89
|
+
filter,
|
|
131
90
|
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
const { pipe } = require('../../function')
|
|
2
|
+
const seq = require('..')
|
|
3
|
+
|
|
4
|
+
/** @type {<T>(a: Iterable<T>) => (b: Iterable<T>) => Iterable<T>} */
|
|
5
|
+
const concat = a => b => ({
|
|
6
|
+
*[Symbol.iterator]() {
|
|
7
|
+
yield* a
|
|
8
|
+
yield* b
|
|
9
|
+
}
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
/** @type {<T, R>(s: seq.Scan<T, R>) => (c: Iterable<T>) => Iterable<R>} */
|
|
13
|
+
const scan = s => c => ({
|
|
14
|
+
*[Symbol.iterator]() {
|
|
15
|
+
let next = s
|
|
16
|
+
for (const i of c) {
|
|
17
|
+
const result = next(i)
|
|
18
|
+
next = result[1]
|
|
19
|
+
yield result[0]
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
/** @type {<T, R>(s: seq.InclusiveScan<T, R>) => (c: Iterable<T>) => Iterable<R>} */
|
|
25
|
+
const inclusiveScan = ([first, s]) => c => concat([first])(scan(s)(c))
|
|
26
|
+
|
|
27
|
+
/** @type {<T, R>(s: seq.InclusiveScan<T, R>) => (c: Iterable<T>) => R} */
|
|
28
|
+
const reduce = ([first, s]) => c => {
|
|
29
|
+
let next = first
|
|
30
|
+
for (const i of scan(s)(c)) {
|
|
31
|
+
next = i
|
|
32
|
+
}
|
|
33
|
+
return next
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const entries = scan(seq.entries)
|
|
37
|
+
|
|
38
|
+
const sum = reduce(seq.sum)
|
|
39
|
+
|
|
40
|
+
const length = reduce(seq.length)
|
|
41
|
+
|
|
42
|
+
const join = pipe(seq.join)(reduce)
|
|
43
|
+
|
|
44
|
+
/** @type {<T, R>(f: (value: T) => Iterable<R>) => (c: Iterable<T>) => Iterable<R>} */
|
|
45
|
+
const flatMap = f => c => ({
|
|
46
|
+
*[Symbol.iterator]() {
|
|
47
|
+
for (const i of c) {
|
|
48
|
+
yield* f(i)
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
/** @type {<T, R>(f: (value: T) => R) => (c: Iterable<T>) => Iterable<R>} */
|
|
54
|
+
const map = seq.map(flatMap)
|
|
55
|
+
|
|
56
|
+
/** @type {<T>(f: (value: T) => boolean) => (c: Iterable<T>) => Iterable<T>} */
|
|
57
|
+
const filter = seq.filter(flatMap)
|
|
58
|
+
|
|
59
|
+
/** @type {<T>(c: Iterable<Iterable<T>>) => Iterable<T>} */
|
|
60
|
+
const flat = flatMap(x => x)
|
|
61
|
+
|
|
62
|
+
/** @type {<T>(f: (value: T) => boolean) => (c: Iterable<T>) => Iterable<T>} */
|
|
63
|
+
const takeWhile = f => c => ({
|
|
64
|
+
*[Symbol.iterator]() {
|
|
65
|
+
for (const i of c) {
|
|
66
|
+
if (!f(i)) { return }
|
|
67
|
+
yield i
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
/** @type {<T>(_: (_: T) => boolean) => (_: Iterable<T>) => T|undefined} */
|
|
73
|
+
const find = f => c => {
|
|
74
|
+
for (const i of c) {
|
|
75
|
+
if (f(i)) {
|
|
76
|
+
return i
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return undefined
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
module.exports = {
|
|
83
|
+
/** @readonly */
|
|
84
|
+
reduce,
|
|
85
|
+
/** @readonly */
|
|
86
|
+
join,
|
|
87
|
+
/** @readonly */
|
|
88
|
+
sum,
|
|
89
|
+
/** @readonly */
|
|
90
|
+
length,
|
|
91
|
+
/** @readonly */
|
|
92
|
+
entries,
|
|
93
|
+
/** @readonly */
|
|
94
|
+
scan,
|
|
95
|
+
/** @readonly */
|
|
96
|
+
inclusiveScan,
|
|
97
|
+
/** @readonly */
|
|
98
|
+
flatMap,
|
|
99
|
+
/** @readonly */
|
|
100
|
+
map,
|
|
101
|
+
/** @readonly */
|
|
102
|
+
filter,
|
|
103
|
+
/** @readonly */
|
|
104
|
+
flat,
|
|
105
|
+
/** @readonly */
|
|
106
|
+
takeWhile,
|
|
107
|
+
/** @readonly */
|
|
108
|
+
find,
|
|
109
|
+
}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
const array = require('../array')
|
|
2
|
+
const option = require('../../option')
|
|
3
|
+
const base = require('..')
|
|
4
|
+
const { pipe } = require('../../function')
|
|
5
|
+
const { todo } = require('../../dev')
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @template T
|
|
9
|
+
* @typedef {() => Result<T>} List
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @template T
|
|
14
|
+
* @typedef {FirstAndTail<T>|undefined} Result<T>
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @template T
|
|
19
|
+
* @typedef {array.Tuple2<T, List<T>>} FirstAndTail
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
const empty = () => undefined
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @template T
|
|
26
|
+
* @template R
|
|
27
|
+
* @typedef {(list: List<T>) => List<R>} ListMap
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
/** @type {<T>(first: T) => ListMap<T, T>} */
|
|
31
|
+
const list = first => tail => () => [first, tail]
|
|
32
|
+
|
|
33
|
+
/** @type {<T>(first: T) => List<T>} */
|
|
34
|
+
const one = first => list(first)(empty)
|
|
35
|
+
|
|
36
|
+
/** @type {<T>(array: array.Array<T>) => List<T>} */
|
|
37
|
+
const fromArray = a => {
|
|
38
|
+
/** @typedef {typeof a extends array.Array<infer T> ? T : never} T */
|
|
39
|
+
/** @type {(index: number) => List<T>} */
|
|
40
|
+
const at = index => {
|
|
41
|
+
/** @type {(value: readonly [T]) => Result<T>} */
|
|
42
|
+
const result = ([value]) => list(value)(at(index + 1))()
|
|
43
|
+
return () => option.map(result)(array.at(index)(a))
|
|
44
|
+
}
|
|
45
|
+
return at(0)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Note: the function is not completly lazy.
|
|
50
|
+
* it calls `a()` as soon as `a` and `b` are provided.
|
|
51
|
+
* Othrewise we may have a stack overflow if a list
|
|
52
|
+
* contains a lot of concateneted empty lists.
|
|
53
|
+
* And we can't relay on ES6 TCO (Tail Call Optimization)
|
|
54
|
+
* because it's not supported by Chrome and Firefox.
|
|
55
|
+
* @type {<T>(list0: List<T>) => ListMap<T, T>}
|
|
56
|
+
*/
|
|
57
|
+
const concat = a => b => {
|
|
58
|
+
const result = a()
|
|
59
|
+
if (result !== undefined) {
|
|
60
|
+
const [first, tail] = result
|
|
61
|
+
return () => [first, concat(tail)(b)]
|
|
62
|
+
}
|
|
63
|
+
return b
|
|
64
|
+
// /** @typedef {typeof a extends List<infer T> ? T : never} T */
|
|
65
|
+
// /** @type {(firstAntTail: FirstAndTail<T>) => Result<T>} */
|
|
66
|
+
// const defined = ([first, tail]) => [first, concat(tail)(b)]
|
|
67
|
+
// return option.match(defined)(b)(a())
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** @type {<T, R>(f: (value: T) => List<R>) => ListMap<T, R>} */
|
|
71
|
+
const flatMap = f => input => () => {
|
|
72
|
+
let i = input
|
|
73
|
+
while (true) {
|
|
74
|
+
const result = i()
|
|
75
|
+
if (result === undefined) { return undefined }
|
|
76
|
+
const [first, tail] = result
|
|
77
|
+
const firstResult = f(first)()
|
|
78
|
+
if (firstResult !== undefined) {
|
|
79
|
+
const [firstFirst, firstTail] = firstResult
|
|
80
|
+
return [firstFirst, concat(firstTail)(flatMap(f)(tail))]
|
|
81
|
+
}
|
|
82
|
+
i = tail
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** @type {<T>(list: List<List<T>>) => List<T>} */
|
|
87
|
+
const flat = flatMap(i => i)
|
|
88
|
+
|
|
89
|
+
/** @type {<T, R>(f: (value: T) => R) => ListMap<T, R>} */
|
|
90
|
+
const map = f => flatMap(i => one(f(i)))
|
|
91
|
+
|
|
92
|
+
/** @type {<T>(f: (value: T) => boolean) => ListMap<T, T>} */
|
|
93
|
+
const filter = f => flatMap(i => f(i) ? one(i) : empty)
|
|
94
|
+
|
|
95
|
+
/** @type {<T, R>(s: base.Scan<T, R>) => ListMap<T, R>} */
|
|
96
|
+
const scan = s => input => () => {
|
|
97
|
+
/** @typedef {typeof s extends base.Scan<infer T, infer R> ? [T, R] : never} TR */
|
|
98
|
+
/** @typedef {TR[0]} T */
|
|
99
|
+
/** @typedef {TR[1]} R */
|
|
100
|
+
/** @type {(firstAndTail: FirstAndTail<T>) => Result<R>} */
|
|
101
|
+
const defined = ([first, tail]) => {
|
|
102
|
+
const [newFirst, newS] = s(first)
|
|
103
|
+
return [newFirst, scan(newS)(tail)]
|
|
104
|
+
}
|
|
105
|
+
return option.map(defined)(input())
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** @type {<T, R>(s: base.InclusiveScan<T, R>) => ListMap<T, R>} */
|
|
109
|
+
const inclusiveScan = ([first, s]) => input => list(first)(scan(s)(input))
|
|
110
|
+
|
|
111
|
+
/** @type {<T>(def: T) => (input: List<T>) => T} */
|
|
112
|
+
const last = def => input => {
|
|
113
|
+
let i = input()
|
|
114
|
+
let r = def
|
|
115
|
+
while (i !== undefined) {
|
|
116
|
+
r = i[0]
|
|
117
|
+
i = i[1]()
|
|
118
|
+
}
|
|
119
|
+
return r
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** @type {<T, R>(s: base.InclusiveScan<T, R>) => (input: List<T>) => R} */
|
|
123
|
+
const reduce = s => input => last(s[0])(inclusiveScan(s)(input))
|
|
124
|
+
|
|
125
|
+
const entries = scan(base.entries)
|
|
126
|
+
|
|
127
|
+
const sum = reduce(base.sum)
|
|
128
|
+
|
|
129
|
+
const length = reduce(base.length)
|
|
130
|
+
|
|
131
|
+
const join = pipe(base.join)(reduce)
|
|
132
|
+
|
|
133
|
+
/** @type {<T>(f: (value: T) => boolean) => (input: List<T>) => T|undefined} */
|
|
134
|
+
const find = f => input => {
|
|
135
|
+
/** @typedef {typeof f extends (value: infer T) => boolean ? T : never} T */
|
|
136
|
+
/** @type {(result: FirstAndTail<T>) => T} */
|
|
137
|
+
const defined = ([first]) => first
|
|
138
|
+
return option.map(defined)(filter(f)(input)())
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Note: probably, it's possible to implement using the `scan` concept.
|
|
143
|
+
* @type {<T>(list: List<T>) => Iterable<T>}
|
|
144
|
+
*/
|
|
145
|
+
const iterable = list => ({
|
|
146
|
+
*[Symbol.iterator]() {
|
|
147
|
+
let result = list()
|
|
148
|
+
while (result !== undefined) {
|
|
149
|
+
yield result[0]
|
|
150
|
+
result = result[1]()
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
module.exports = {
|
|
156
|
+
/** @readonly */
|
|
157
|
+
list,
|
|
158
|
+
/** @readonly */
|
|
159
|
+
one,
|
|
160
|
+
/** @readonly */
|
|
161
|
+
empty,
|
|
162
|
+
/** @readonly */
|
|
163
|
+
concat,
|
|
164
|
+
/** @readonly */
|
|
165
|
+
fromArray,
|
|
166
|
+
/** @readonly */
|
|
167
|
+
iterable,
|
|
168
|
+
/** @readonly */
|
|
169
|
+
flatMap,
|
|
170
|
+
/** @readonly */
|
|
171
|
+
flat,
|
|
172
|
+
/** @readonly */
|
|
173
|
+
map,
|
|
174
|
+
/** @readonly */
|
|
175
|
+
filter,
|
|
176
|
+
/** @readonly */
|
|
177
|
+
scan,
|
|
178
|
+
/** @readonly */
|
|
179
|
+
inclusiveScan,
|
|
180
|
+
/** @readonly */
|
|
181
|
+
last,
|
|
182
|
+
/** @readonly */
|
|
183
|
+
reduce,
|
|
184
|
+
/** @readonly */
|
|
185
|
+
entries,
|
|
186
|
+
/** @readonly */
|
|
187
|
+
sum,
|
|
188
|
+
/** @readonly */
|
|
189
|
+
join,
|
|
190
|
+
/** @readonly */
|
|
191
|
+
length,
|
|
192
|
+
/** @readonly */
|
|
193
|
+
find,
|
|
194
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
const list = require('.')
|
|
2
|
+
const { sum } = require('..')
|
|
3
|
+
|
|
4
|
+
/** @type {<T>(l: list.List<T>) => void} */
|
|
5
|
+
const print = a => {
|
|
6
|
+
let i = a()
|
|
7
|
+
while (i !== undefined) {
|
|
8
|
+
console.log(i[0])
|
|
9
|
+
i = i[1]()
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
{
|
|
14
|
+
const big = list.fromArray([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 42, 60])
|
|
15
|
+
const list0 = list.fromArray([0, 1, 2, 3])
|
|
16
|
+
const list1 = list.flatMap(x => list.fromArray([x, x * 2, x * 3]))(list0)
|
|
17
|
+
const list2 = list.concat(list0)(list0)
|
|
18
|
+
const list3 = list.inclusiveScan(sum)(list0)
|
|
19
|
+
const r = list.find(x => x === 42)(big)
|
|
20
|
+
{
|
|
21
|
+
let x = big
|
|
22
|
+
for (let i = 0; i < 10000; ++i) {
|
|
23
|
+
x = list.concat(list.empty)(x)
|
|
24
|
+
}
|
|
25
|
+
const r = x()
|
|
26
|
+
print(x)
|
|
27
|
+
}
|
|
28
|
+
{
|
|
29
|
+
let x = big
|
|
30
|
+
for (let i = 0; i < 10000; ++i) {
|
|
31
|
+
x = list.concat(x)(list.empty)
|
|
32
|
+
}
|
|
33
|
+
const r = x()
|
|
34
|
+
print(x)
|
|
35
|
+
}
|
|
36
|
+
}
|
package/test.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
const i = require('./')
|
|
2
2
|
|
|
3
|
-
require('./
|
|
4
|
-
require('./
|
|
3
|
+
require('./sequence/list/test')
|
|
4
|
+
require('./btree/test')
|
|
5
|
+
require('./sequence/iterable/test')
|
|
6
|
+
require('./sequence/asyncIterable/test')
|
|
5
7
|
require('./module-manager/test')
|
|
6
8
|
|
|
7
9
|
/** @type {() => never} */
|
package/async/iterable/index.js
DELETED
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
const { pipe } = require('../../function')
|
|
2
|
-
const seq = require('../../sequence')
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* @template T
|
|
6
|
-
* @typedef {Promise<T>|T} PromiseOrValue
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* @template T
|
|
11
|
-
* @template R
|
|
12
|
-
* @typedef {(f: (value: T) => PromiseOrValue<R>) => (c: AsyncIterable<T>) => AsyncIterable<R>} Map
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* @template T
|
|
17
|
-
* @typedef {Iterable<T> | AsyncIterable<T>} AnyIterable
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
/** @type {<T, R>(f: (value: T) => PromiseOrValue<R>) => (c: AnyIterable<T>) => AsyncIterable<R>} */
|
|
21
|
-
const map = f => c => ({
|
|
22
|
-
async *[Symbol.asyncIterator]() {
|
|
23
|
-
for await (const i of c) {
|
|
24
|
-
yield f(i)
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
/** @type {<T>(c: AnyIterable<AnyIterable<T>>) => AsyncIterable<T>} */
|
|
30
|
-
const flatten = c => ({
|
|
31
|
-
async *[Symbol.asyncIterator]() {
|
|
32
|
-
for await (const i of c) {
|
|
33
|
-
yield *i
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
/** @type {<T>(f: (value: T) => Promise<boolean>) => (c: AnyIterable<T>) => AnyIterable<T>} */
|
|
39
|
-
const filter = f => c => ({
|
|
40
|
-
async *[Symbol.asyncIterator]() {
|
|
41
|
-
for await (const i of c) {
|
|
42
|
-
if (await f(i)) {
|
|
43
|
-
yield i
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
/** @type {<T, R>(f: (value: T) => AnyIterable<R>) => (c: AnyIterable<T>) => AsyncIterable<R>} */
|
|
50
|
-
const flatMap = f => pipe(map(f))(flatten)
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* @template A
|
|
54
|
-
* @template T
|
|
55
|
-
* @typedef {(accumulator: A) => (value: T) => PromiseOrValue<A>} Merge
|
|
56
|
-
*/
|
|
57
|
-
|
|
58
|
-
/** @type {<A, T>(merge: Merge<A, T>) => (init: A) => (c: AnyIterable<T>) => Promise<A>} */
|
|
59
|
-
const reduce = merge => init => async c => {
|
|
60
|
-
let result = init
|
|
61
|
-
for await (const i of c) {
|
|
62
|
-
result = await merge(result)(i)
|
|
63
|
-
}
|
|
64
|
-
return result
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/** @type {<T>(a: AnyIterable<T>) => (b: AnyIterable<T>) => AsyncIterable<T>} */
|
|
68
|
-
const concat = a => b => ({
|
|
69
|
-
async *[Symbol.asyncIterator]() {
|
|
70
|
-
yield* a
|
|
71
|
-
yield* b
|
|
72
|
-
}
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
/** @type {<A, T>(merg: Merge<A, T>) => (init: A) => (c: AnyIterable<T>) => AsyncIterable<A>} */
|
|
76
|
-
const exclusiveScan = merge => init => c => ({
|
|
77
|
-
async *[Symbol.asyncIterator]() {
|
|
78
|
-
let result = init
|
|
79
|
-
for await (const i of c) {
|
|
80
|
-
result = await merge(result)(i)
|
|
81
|
-
yield result
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
/** @type {<T, R>(es: seq.Scan<T, R>) => (c: AnyIterable<T>) => AsyncIterable<R>} */
|
|
87
|
-
const applyExclusiveScan = es => c => ({
|
|
88
|
-
async *[Symbol.asyncIterator]() {
|
|
89
|
-
let ies = es
|
|
90
|
-
for await (const i of c) {
|
|
91
|
-
const result = ies(i)
|
|
92
|
-
ies = result[1]
|
|
93
|
-
yield result[0]
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
})
|
|
97
|
-
|
|
98
|
-
/** @type {<A, T>(merge: Merge<A, T>) => (init: A) => (c: AnyIterable<T>) => AsyncIterable<A>} */
|
|
99
|
-
const inclusiveScan = merge => init => c => concat([init])(exclusiveScan(merge)(init)(c))
|
|
100
|
-
|
|
101
|
-
/** @type {<I, S, R>(op: seq.Operation<I, S, R>) => (_: AnyIterable<I>) => Promise<R>} */
|
|
102
|
-
const apply = ({ merge, init, result }) => async c => result(await reduce(merge)(init)(c))
|
|
103
|
-
|
|
104
|
-
const sum = apply(seq.sum)
|
|
105
|
-
|
|
106
|
-
const join = pipe(seq.join)(apply)
|
|
107
|
-
|
|
108
|
-
const size = apply(seq.size)
|
|
109
|
-
|
|
110
|
-
module.exports = {
|
|
111
|
-
/** @readonly */
|
|
112
|
-
apply,
|
|
113
|
-
/** @readonly */
|
|
114
|
-
concat,
|
|
115
|
-
/** @readonly */
|
|
116
|
-
map,
|
|
117
|
-
/** @readonly */
|
|
118
|
-
filter,
|
|
119
|
-
/** @readonly */
|
|
120
|
-
flatMap,
|
|
121
|
-
/** @readonly */
|
|
122
|
-
reduce,
|
|
123
|
-
/** @readonly */
|
|
124
|
-
sum,
|
|
125
|
-
/** @readonly */
|
|
126
|
-
size,
|
|
127
|
-
/** @readonly */
|
|
128
|
-
join,
|
|
129
|
-
/** @readonly */
|
|
130
|
-
exclusiveScan,
|
|
131
|
-
/** @readonly */
|
|
132
|
-
inclusiveScan,
|
|
133
|
-
}
|
package/iterable/index.js
DELETED
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
const { pipe } = require('../function')
|
|
2
|
-
const seq = require('../sequence')
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* @template S
|
|
6
|
-
* @template T
|
|
7
|
-
* @typedef {(_: S) => (_: T) => S} Merge
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
/** @type {<T, R>(merge: Merge<R, T>) => (init: R) => (_: Iterable<T>) => R} */
|
|
11
|
-
const reduce = merge => init => c => {
|
|
12
|
-
let result = init
|
|
13
|
-
for (const i of c) {
|
|
14
|
-
result = merge(result)(i)
|
|
15
|
-
}
|
|
16
|
-
return result
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/** @type {<T>(a: Iterable<T>) => (b: Iterable<T>) => Iterable<T>} */
|
|
20
|
-
const concat = a => b => ({
|
|
21
|
-
*[Symbol.iterator]() {
|
|
22
|
-
yield *a
|
|
23
|
-
yield *b
|
|
24
|
-
}
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
/** @type {<A, T>(merge: Merge<A, T>) => (init: A) => (c: Iterable<T>) => Iterable<A>} */
|
|
28
|
-
const exclusiveScan = merge => init => c => ({
|
|
29
|
-
*[Symbol.iterator]() {
|
|
30
|
-
let result = init
|
|
31
|
-
for (const i of c) {
|
|
32
|
-
result = merge(result)(i)
|
|
33
|
-
yield result
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
/** @type {<A, T>(merge: Merge<A, T>) => (init: A) => (c: Iterable<T>) => Iterable<A>} */
|
|
39
|
-
const inclusiveScan = merge => init => c => concat([init])(exclusiveScan(merge)(init)(c))
|
|
40
|
-
|
|
41
|
-
/** @type {<T, R>(es: seq.Scan<T, R>) => (c: Iterable<T>) => Iterable<R>} */
|
|
42
|
-
const applyScan = es => c => ({
|
|
43
|
-
*[Symbol.iterator]() {
|
|
44
|
-
let ies = es
|
|
45
|
-
for (const i of c) {
|
|
46
|
-
const result = ies(i)
|
|
47
|
-
ies = result[1]
|
|
48
|
-
yield result[0]
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
/** @type {<T, R>(is: seq.InclusiveScan<T, R>) => (c: Iterable<T>) => Iterable<R>} */
|
|
54
|
-
const applyInclusiveScan = ({scan, first}) => c => concat([first])(applyScan(scan)(c))
|
|
55
|
-
|
|
56
|
-
const entries = applyScan(seq.entries)
|
|
57
|
-
|
|
58
|
-
/** @type {<I, S, R>(op: seq.Operation<I, S, R>) => (_: Iterable<I>) => R} */
|
|
59
|
-
const apply = ({ merge, init, result }) => pipe(reduce(merge)(init))(result)
|
|
60
|
-
|
|
61
|
-
const sum = apply(seq.sum)
|
|
62
|
-
|
|
63
|
-
const size = apply(seq.size)
|
|
64
|
-
|
|
65
|
-
const join = pipe(seq.join)(apply)
|
|
66
|
-
|
|
67
|
-
/** @type {<T, R>(f: (value: T) => R) => (c: Iterable<T>) => Iterable<R>} */
|
|
68
|
-
const map = f => c => ({
|
|
69
|
-
*[Symbol.iterator]() {
|
|
70
|
-
for (const i of c) {
|
|
71
|
-
yield f(i)
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
/** @type {<T>(_: (_: T) => boolean) => (_: Iterable<T>) => T|undefined} */
|
|
77
|
-
const find = f => c => {
|
|
78
|
-
for (const i of c) {
|
|
79
|
-
if (f(i)) {
|
|
80
|
-
return i
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
return undefined
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
module.exports = {
|
|
87
|
-
/** @readonly */
|
|
88
|
-
apply,
|
|
89
|
-
|
|
90
|
-
/** @readonly */
|
|
91
|
-
reduce,
|
|
92
|
-
|
|
93
|
-
/** @readonly */
|
|
94
|
-
join,
|
|
95
|
-
|
|
96
|
-
/** @readonly */
|
|
97
|
-
sum,
|
|
98
|
-
|
|
99
|
-
/** @readonly */
|
|
100
|
-
size,
|
|
101
|
-
|
|
102
|
-
/** @readonly */
|
|
103
|
-
entries,
|
|
104
|
-
|
|
105
|
-
/** @readonly */
|
|
106
|
-
map,
|
|
107
|
-
|
|
108
|
-
/** @readonly */
|
|
109
|
-
exclusiveScan,
|
|
110
|
-
|
|
111
|
-
/** @readonly */
|
|
112
|
-
inclusiveScan,
|
|
113
|
-
|
|
114
|
-
/** @readonly */
|
|
115
|
-
find,
|
|
116
|
-
}
|