functionalscript 0.0.185 → 0.0.191
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 +15 -47
- package/btree/test.js +3 -5
- package/json/index.js +89 -0
- package/json/test.js +18 -0
- package/map/index.js +10 -4
- package/map/test.js +1 -1
- package/module-manager/index.js +1 -1
- package/package.json +1 -1
- package/sequence/asyncIterable/index.js +1 -1
- package/sequence/index.js +300 -48
- package/sequence/iterable/index.js +1 -1
- package/sequence/operator/index.js +92 -0
- package/sequence/test.js +62 -0
- package/test.js +2 -1
- package/sequence/list/index.js +0 -305
- package/sequence/list/test.js +0 -43
package/btree/index.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
const { index3, index5 } = require('../cmp')
|
|
2
|
-
const
|
|
3
|
-
const { pipe } = require('../function')
|
|
2
|
+
const seq = require('../sequence')
|
|
4
3
|
|
|
5
4
|
/**
|
|
6
5
|
* @template T
|
|
@@ -306,64 +305,33 @@ const replaceVisitor = {
|
|
|
306
305
|
notFound: notFoundGet,
|
|
307
306
|
}
|
|
308
307
|
|
|
309
|
-
/** @type {<T>(
|
|
310
|
-
const values = node => ({
|
|
311
|
-
*[Symbol.iterator]() {
|
|
312
|
-
switch (node.length) {
|
|
313
|
-
case 1: case 2: {
|
|
314
|
-
yield* node
|
|
315
|
-
return
|
|
316
|
-
}
|
|
317
|
-
case 3: {
|
|
318
|
-
yield* values(node[0])
|
|
319
|
-
yield node[1]
|
|
320
|
-
yield* values(node[2])
|
|
321
|
-
return
|
|
322
|
-
}
|
|
323
|
-
default: {
|
|
324
|
-
yield* values(node[0])
|
|
325
|
-
yield node[1]
|
|
326
|
-
yield* values(node[2])
|
|
327
|
-
yield node[3]
|
|
328
|
-
yield* values(node[4])
|
|
329
|
-
return
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
})
|
|
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 => () => {
|
|
308
|
+
/** @type {<T>(node: Node<T>) => seq.Sequence<T>} */
|
|
309
|
+
const values = node => () => {
|
|
340
310
|
const f = () => {
|
|
341
311
|
switch (node.length) {
|
|
342
|
-
case 1: case 2: { return list
|
|
312
|
+
case 1: case 2: { return seq.list(...node) }
|
|
343
313
|
case 3: {
|
|
344
|
-
return
|
|
345
|
-
|
|
346
|
-
list
|
|
347
|
-
|
|
314
|
+
return seq.concat(
|
|
315
|
+
values(node[0]),
|
|
316
|
+
seq.list(node[1]),
|
|
317
|
+
values(node[2])
|
|
348
318
|
)
|
|
349
319
|
}
|
|
350
320
|
default: {
|
|
351
|
-
return
|
|
352
|
-
|
|
353
|
-
list
|
|
354
|
-
|
|
355
|
-
list
|
|
356
|
-
|
|
321
|
+
return seq.concat(
|
|
322
|
+
values(node[0]),
|
|
323
|
+
seq.list(node[1]),
|
|
324
|
+
values(node[2]),
|
|
325
|
+
seq.list(node[3]),
|
|
326
|
+
values(node[4])
|
|
357
327
|
)
|
|
358
328
|
}
|
|
359
329
|
}
|
|
360
330
|
}
|
|
361
|
-
return
|
|
331
|
+
return seq.next(f())
|
|
362
332
|
}
|
|
363
333
|
|
|
364
334
|
module.exports = {
|
|
365
|
-
/** @readonly */
|
|
366
|
-
valuesList,
|
|
367
335
|
/** @readonly */
|
|
368
336
|
values,
|
|
369
337
|
/**
|
package/btree/test.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const btree = require('.')
|
|
2
|
-
const { setVisitor, valuesList } = btree
|
|
2
|
+
const { setVisitor, values: valuesList } = btree
|
|
3
3
|
const { cmp } = require('../cmp')
|
|
4
|
-
const list = require('../sequence
|
|
4
|
+
const list = require('../sequence')
|
|
5
5
|
|
|
6
6
|
/** @type {(node: btree.Node<string>) => (value: string) => btree.Node<string>} */
|
|
7
7
|
const set = node => value => {
|
|
@@ -21,11 +21,9 @@ const test = () => {
|
|
|
21
21
|
node = set(node)('f')
|
|
22
22
|
//
|
|
23
23
|
{
|
|
24
|
-
/** @type {import('../sequence
|
|
24
|
+
/** @type {import('../sequence').Result<string>} */
|
|
25
25
|
let result = list.next(valuesList(node))
|
|
26
26
|
while (result !== undefined) {
|
|
27
|
-
const t = result[0]
|
|
28
|
-
console.log(t)
|
|
29
27
|
result = list.next(result[1])
|
|
30
28
|
}
|
|
31
29
|
}
|
package/json/index.js
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
const seq = require('../sequence')
|
|
2
|
+
const map = require('../map')
|
|
3
|
+
const op = require('../sequence/operator')
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @typedef {{
|
|
7
|
+
* readonly [k in string]: Json
|
|
8
|
+
* }} Object
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/** @typedef {readonly Json[]} Array */
|
|
12
|
+
|
|
13
|
+
/** @typedef {Object|boolean|string|number|null|Array} Json */
|
|
14
|
+
|
|
15
|
+
/** @type {(value: Json) => (path: readonly string[]) => (src: Json|undefined) => Json} */
|
|
16
|
+
const addProperty = value => {
|
|
17
|
+
/** @type {(path: seq.Sequence<string>) => (src: Json|undefined) => Json} */
|
|
18
|
+
const f = path => src => {
|
|
19
|
+
const result = seq.next(path)
|
|
20
|
+
if (result === undefined) { return value }
|
|
21
|
+
const srcObject = (src === undefined || src === null || typeof src !== 'object' || src instanceof Array) ? {} : src
|
|
22
|
+
const [name, tail] = result
|
|
23
|
+
return { ...srcObject, [name]: f(tail)(srcObject[name]) }
|
|
24
|
+
}
|
|
25
|
+
return path => f(seq.fromArray(path))
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** @type {(kv: readonly[string, seq.Sequence<string>]) => seq.Sequence<string>} */
|
|
29
|
+
const property = ([k, v]) => seq.concat(seq.list(JSON.stringify(k)), seq.list(':'), v)
|
|
30
|
+
|
|
31
|
+
/** @type {op.Scan<seq.Sequence<string>, seq.Sequence<string>>} */
|
|
32
|
+
const commaValue = a => [seq.concat(seq.list(','), a), commaValue]
|
|
33
|
+
|
|
34
|
+
/** @type {op.Scan<seq.Sequence<string>, seq.Sequence<string>>} */
|
|
35
|
+
const joinScan = value => [value, commaValue]
|
|
36
|
+
|
|
37
|
+
/** @type {seq.SequenceMap<seq.Sequence<string>, string>} */
|
|
38
|
+
const join = input => seq.flat(seq.scan(joinScan)(input))
|
|
39
|
+
|
|
40
|
+
/** @type {(open: string) => (close: string) => (input: seq.Sequence<seq.Sequence<string>>) => seq.Sequence<string>} */
|
|
41
|
+
const list = open => close => {
|
|
42
|
+
const seqOpen = seq.list(open)
|
|
43
|
+
const seqClose = seq.list(close)
|
|
44
|
+
return input => seq.concat(seqOpen, join(input), seqClose)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const objectList = list('{')('}')
|
|
48
|
+
|
|
49
|
+
const arrayList = list('[')(']')
|
|
50
|
+
|
|
51
|
+
/** @type {(object: Object) => seq.Sequence<string>} */
|
|
52
|
+
const objectStringify = object => {
|
|
53
|
+
/** @type {map.Map<seq.Sequence<string>>} */
|
|
54
|
+
const m = seq.fold(m => ([k, v]) => m.set(k)(stringSeq(v)))(map.empty)(seq.fromArray(Object.entries(object)))
|
|
55
|
+
return objectList(seq.map(property)(m.entries))
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** @type {(array: Array) => seq.Sequence<string>} */
|
|
59
|
+
const arrayStringify = array => arrayList(seq.map(stringSeq)(seq.fromArray(array)))
|
|
60
|
+
|
|
61
|
+
/** @type {(value: Json) => seq.Sequence<string>} */
|
|
62
|
+
const stringSeq = value => {
|
|
63
|
+
const x = typeof value
|
|
64
|
+
switch (typeof value) {
|
|
65
|
+
case 'boolean': { return seq.list(value ? "true" : "false") }
|
|
66
|
+
// Note: we shouldn't use JSON.stringify since it has non determenistic behavior.
|
|
67
|
+
// In particular: property order could be different.
|
|
68
|
+
case 'number': case 'string': { return seq.list(JSON.stringify(value)) }
|
|
69
|
+
default: {
|
|
70
|
+
if (value === null) { return seq.list("null") }
|
|
71
|
+
if (value instanceof Array) { return arrayStringify(value) }
|
|
72
|
+
return objectStringify(value)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* A deterministic version of `JSON.stringify`
|
|
79
|
+
*
|
|
80
|
+
* @type {(value: Json) => string}
|
|
81
|
+
*/
|
|
82
|
+
const stringify = value => seq.join('')(stringSeq(value))
|
|
83
|
+
|
|
84
|
+
module.exports = {
|
|
85
|
+
/** @readonly */
|
|
86
|
+
addProperty,
|
|
87
|
+
/** @readonly */
|
|
88
|
+
stringify,
|
|
89
|
+
}
|
package/json/test.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const json = require('.')
|
|
2
|
+
|
|
3
|
+
if (json.addProperty("Hello")([])({}) !== "Hello") { throw 'error' }
|
|
4
|
+
|
|
5
|
+
{
|
|
6
|
+
const x = json.stringify(json.addProperty("Hello")(['a'])({}))
|
|
7
|
+
if (x !== '{"a":"Hello"}') { throw x }
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
{
|
|
11
|
+
const x = json.stringify(json.addProperty("Hello")(['a'])({c:[],b:12}))
|
|
12
|
+
if (x !== '{"a":"Hello","b":12,"c":[]}') { throw x }
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
{
|
|
16
|
+
const x = json.stringify(json.addProperty("Hello")(['a', 'x'])({ a: { y: [24] }, c: [], b: 12 }))
|
|
17
|
+
if (x !== '{"a":{"x":"Hello","y":[24]},"b":12,"c":[]}') { throw x }
|
|
18
|
+
}
|
package/map/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
const option = require("../option")
|
|
2
|
-
const { getVisitor, setVisitor, valuesList } = require("../btree")
|
|
2
|
+
const { getVisitor, setVisitor, values: valuesList } = require("../btree")
|
|
3
3
|
const { cmp } = require("../cmp")
|
|
4
|
-
const
|
|
4
|
+
const seq = require("../sequence")
|
|
5
|
+
const op = require("../sequence/operator")
|
|
5
6
|
|
|
6
7
|
/** @typedef {import("../cmp").Sign} Sign */
|
|
7
8
|
|
|
@@ -30,7 +31,7 @@ const list = require("../sequence/list")
|
|
|
30
31
|
* @typedef {{
|
|
31
32
|
* readonly get: (name: string) => T|undefined
|
|
32
33
|
* readonly set: (name: string) => (value: T) => Map<T>
|
|
33
|
-
* readonly entries:
|
|
34
|
+
* readonly entries: seq.Sequence<Entry<T>>
|
|
34
35
|
* readonly root: undefined|TNode<Entry<T>>
|
|
35
36
|
* }} Map
|
|
36
37
|
*/
|
|
@@ -62,11 +63,16 @@ const create = root => ({
|
|
|
62
63
|
const empty = {
|
|
63
64
|
get: () => undefined,
|
|
64
65
|
set: name => value => create([[name, value]]),
|
|
65
|
-
entries:
|
|
66
|
+
entries: seq.empty,
|
|
66
67
|
root: undefined
|
|
67
68
|
}
|
|
68
69
|
|
|
70
|
+
/** @type {<T>(entries: seq.Sequence<Entry<T>>) => Map<T>} */
|
|
71
|
+
const fromEntries = seq.fold(map => entry => map.set(entry))(empty)
|
|
72
|
+
|
|
69
73
|
module.exports = {
|
|
70
74
|
/** @readonly */
|
|
71
75
|
empty,
|
|
76
|
+
/** @readonly */
|
|
77
|
+
fromEntries,
|
|
72
78
|
}
|
package/map/test.js
CHANGED
package/module-manager/index.js
CHANGED
|
@@ -3,7 +3,7 @@ const { pipe } = require('../function')
|
|
|
3
3
|
const option = require('../option')
|
|
4
4
|
const { head, last, splitLast, splitFirst } = array
|
|
5
5
|
const iter = require('../sequence/iterable')
|
|
6
|
-
const seq = require('../sequence')
|
|
6
|
+
const seq = require('../sequence/operator')
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* @template T
|
package/package.json
CHANGED
package/sequence/index.js
CHANGED
|
@@ -1,92 +1,344 @@
|
|
|
1
|
+
const array = require('./array')
|
|
2
|
+
const seqOp = require('./operator')
|
|
3
|
+
const { pipe } = require('../function')
|
|
1
4
|
const op = require('../function/operator')
|
|
5
|
+
const { logicalNot, strictEqual } = require('../function/operator')
|
|
2
6
|
|
|
3
7
|
/**
|
|
4
|
-
* @template
|
|
5
|
-
* @
|
|
6
|
-
* @typedef {import('./array').Tuple2<T0, T1>} Tuple2
|
|
8
|
+
* @template T
|
|
9
|
+
* @typedef {() => Result<T>} SequenceFn
|
|
7
10
|
*/
|
|
8
11
|
|
|
9
12
|
/**
|
|
10
13
|
* @template T
|
|
11
|
-
* @
|
|
12
|
-
* @typedef {Tuple2<R, Scan<T, R>>} ScanResult
|
|
14
|
+
* @typedef {readonly [Sequence<T>, Sequence<T>]} Concat
|
|
13
15
|
*/
|
|
14
16
|
|
|
15
17
|
/**
|
|
18
|
+
* Use `next` function to get `first` and `tail` of the list.
|
|
19
|
+
*
|
|
20
|
+
* Please note that the sequence also contains `Concat<T>. We need this as
|
|
21
|
+
* a workaround because modern JavaScript implementations don't support
|
|
22
|
+
* ES6 TCO (Tail Call Optimization). Without this wotkaround we may have
|
|
23
|
+
* a stack overflow if a list contains a lot of concateneted lists.
|
|
24
|
+
*
|
|
16
25
|
* @template T
|
|
17
|
-
* @
|
|
18
|
-
* @typedef {(value: T) => ScanResult<T, R>} Scan
|
|
26
|
+
* @typedef { SequenceFn<T> | Concat<T>} Sequence
|
|
19
27
|
*/
|
|
20
28
|
|
|
21
29
|
/**
|
|
22
30
|
* @template T
|
|
23
|
-
* @
|
|
24
|
-
* @typedef {Tuple2<R, Scan<T, R>>} ExclusiveScan
|
|
31
|
+
* @typedef {FirstAndTail<T>|undefined} Result<T>
|
|
25
32
|
*/
|
|
26
33
|
|
|
27
|
-
/**
|
|
28
|
-
const scan = operator => {
|
|
29
|
-
/** @typedef {typeof operator extends op.ReduceOperator<infer R, infer T> ? [R, T] : never} RT */
|
|
30
|
-
/** @typedef {RT[0]} R */
|
|
31
|
-
/** @typedef {RT[1]} T */
|
|
32
|
-
/** @type {(prior: R) => Scan<T, R>} */
|
|
33
|
-
const f = prior => value => {
|
|
34
|
-
const result = operator(prior)(value)
|
|
35
|
-
return [result, f(result)]
|
|
36
|
-
}
|
|
37
|
-
return f
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/** @type {<R, T>(operator: op.ReduceOperator<R, T>) => (first: R) => ExclusiveScan<T, R>} */
|
|
41
|
-
const exclusiveScan = operator => first => [first, scan(operator)(first)]
|
|
42
|
-
|
|
43
|
-
/**
|
|
34
|
+
/**
|
|
44
35
|
* @template T
|
|
45
|
-
* @typedef {Tuple2<
|
|
36
|
+
* @typedef {array.Tuple2<T, Sequence<T>>} FirstAndTail
|
|
46
37
|
*/
|
|
47
38
|
|
|
48
|
-
|
|
49
|
-
const createEntries = index => value => [[index, value], createEntries(index + 1)]
|
|
50
|
-
|
|
51
|
-
const entries = createEntries(0)
|
|
39
|
+
const empty = () => undefined
|
|
52
40
|
|
|
53
|
-
/** @type {(
|
|
54
|
-
const
|
|
41
|
+
/** @type {<F, T>(a: readonly[F, Sequence<T>]) => (b: Sequence<T>) => readonly[F, Sequence<T>]} */
|
|
42
|
+
const norm = ([a0, a1]) => b => [a0, [a1, b]]
|
|
55
43
|
|
|
56
|
-
|
|
44
|
+
/** @type {<T>(input: Sequence<T>) => Result<T>} */
|
|
45
|
+
const next = input => {
|
|
46
|
+
let i = input
|
|
47
|
+
while (true) {
|
|
48
|
+
if (typeof i === 'function') { return i() }
|
|
49
|
+
const [a, b] = i
|
|
50
|
+
if (typeof a === 'function') {
|
|
51
|
+
const result = a()
|
|
52
|
+
if (result !== undefined) {
|
|
53
|
+
return norm(result)(b)
|
|
54
|
+
}
|
|
55
|
+
i = b
|
|
56
|
+
} else {
|
|
57
|
+
i = norm(a)(b)
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
57
61
|
|
|
58
|
-
/** @type {(
|
|
59
|
-
const
|
|
62
|
+
/** @type {<T>(input: Sequence<T>) => T|undefined} */
|
|
63
|
+
const first = input => {
|
|
64
|
+
const result = next(input)
|
|
65
|
+
if (result === undefined) { return undefined }
|
|
66
|
+
return result[0]
|
|
67
|
+
}
|
|
60
68
|
|
|
61
|
-
|
|
69
|
+
/**
|
|
70
|
+
* @template T
|
|
71
|
+
* @template R
|
|
72
|
+
* @typedef {(list: Sequence<T>) => Sequence<R>} SequenceMap
|
|
73
|
+
*/
|
|
62
74
|
|
|
63
75
|
/**
|
|
64
76
|
* @template T
|
|
65
77
|
* @template R
|
|
66
|
-
* @typedef {(
|
|
78
|
+
* @typedef {(list: Sequence<T>) => R} SequenceReduce
|
|
67
79
|
*/
|
|
68
80
|
|
|
69
|
-
/** @type {<T
|
|
70
|
-
const
|
|
81
|
+
/** @type {<T>(...array: readonly T[]) => Sequence<T>} */
|
|
82
|
+
const list = (...array) => {
|
|
83
|
+
/** @typedef {typeof array extends readonly(infer T)[] ? T : never} T */
|
|
84
|
+
let i = array.length
|
|
85
|
+
/** @type {Sequence<T>} */
|
|
86
|
+
let tail = empty
|
|
87
|
+
while (true) {
|
|
88
|
+
if (i === 0) { return tail }
|
|
89
|
+
i = i - 1
|
|
90
|
+
/** @type {FirstAndTail<T>} */
|
|
91
|
+
const result = [array[i], tail]
|
|
92
|
+
tail = () => result
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** @type {<T>(array: array.Array<T>) => Sequence<T>} */
|
|
97
|
+
const fromArray = a => {
|
|
98
|
+
/** @typedef {typeof a extends array.Array<infer T> ? T : never} T */
|
|
99
|
+
/** @type {(index: number) => Sequence<T>} */
|
|
100
|
+
const at = index => () => {
|
|
101
|
+
const result = array.at(index)(a)
|
|
102
|
+
if (result === undefined) { return undefined }
|
|
103
|
+
return [result[0], at(index + 1)]
|
|
104
|
+
}
|
|
105
|
+
return at(0)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** @type {<T>(...array: readonly Sequence<T>[]) => Sequence<T>} */
|
|
109
|
+
const concat = (...array) => {
|
|
110
|
+
let i = array.length
|
|
111
|
+
if (i == 0) { return empty }
|
|
112
|
+
i = i - 1
|
|
113
|
+
let tail = array[i]
|
|
114
|
+
while (true) {
|
|
115
|
+
if (i === 0) { return tail }
|
|
116
|
+
i = i - 1
|
|
117
|
+
tail = [array[i], tail]
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** @type {(_: number) => Sequence<number>} */
|
|
122
|
+
const generate = n => {
|
|
123
|
+
/** @type {(_: number) => Sequence<number>} */
|
|
124
|
+
const f = i => () => {
|
|
125
|
+
if (n <= i) { return undefined }
|
|
126
|
+
return [i, f(i + 1)]
|
|
127
|
+
}
|
|
128
|
+
return f(0)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** @type {<T, R>(f: (value: T) => Sequence<R>) => SequenceMap<T, R>} */
|
|
132
|
+
const flatMap = f => input => () => {
|
|
133
|
+
let i = input
|
|
134
|
+
while (true) {
|
|
135
|
+
const result = next(i)
|
|
136
|
+
if (result === undefined) { return undefined }
|
|
137
|
+
const [first, tail] = result
|
|
138
|
+
const firstResult = next(f(first))
|
|
139
|
+
if (firstResult !== undefined) {
|
|
140
|
+
return norm(firstResult)(flatMap(f)(tail))
|
|
141
|
+
}
|
|
142
|
+
i = tail
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** @type {<T>(list: Sequence<Sequence<T>>) => Sequence<T>} */
|
|
147
|
+
const flat = flatMap(i => i)
|
|
148
|
+
|
|
149
|
+
/** @type {<T, R>(f: (value: T) => R) => SequenceMap<T, R>} */
|
|
150
|
+
const map = f => flatMap(i => list(f(i)))
|
|
151
|
+
|
|
152
|
+
/** @type {<T>(f: (value: T) => boolean) => SequenceMap<T, T>} */
|
|
153
|
+
const filter = f => flatMap(i => f(i) ? list(i) : empty)
|
|
154
|
+
|
|
155
|
+
/** @type {<T, R>(f: (value: T) => R|undefined) => (value: T) => Sequence<R>} */
|
|
156
|
+
const filterMapFunc = f => i => {
|
|
157
|
+
const result = f(i)
|
|
158
|
+
if (result === undefined) { return empty }
|
|
159
|
+
return list(result)
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/** @type {<T, R>(f: (value: T) => R|undefined) => SequenceMap<T, R>} */
|
|
163
|
+
const filterMap = f => flatMap(filterMapFunc(f))
|
|
164
|
+
|
|
165
|
+
/** @type {<T, R>(s: seqOp.Scan<T, R>) => SequenceMap<T, R>} */
|
|
166
|
+
const scan = s => input => () => {
|
|
167
|
+
const result = next(input)
|
|
168
|
+
if (result === undefined) {
|
|
169
|
+
return result
|
|
170
|
+
}
|
|
171
|
+
const [first, tail] = result
|
|
172
|
+
const [newFirst, newS] = s(first)
|
|
173
|
+
return [newFirst, scan(newS)(tail)]
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/** @type {<T, R>(s: seqOp.ExclusiveScan<T, R>) => SequenceMap<T, R>} */
|
|
177
|
+
const exclusiveScan = ([first, s]) => input => () => [first, scan(s)(input)]
|
|
178
|
+
|
|
179
|
+
/** @type {<T>(def: T) => (input: Sequence<T>) => T} */
|
|
180
|
+
const last = def => input => {
|
|
181
|
+
let r = def
|
|
182
|
+
let i = input
|
|
183
|
+
while (true) {
|
|
184
|
+
const result = next(i)
|
|
185
|
+
if (result === undefined) {
|
|
186
|
+
return r
|
|
187
|
+
}
|
|
188
|
+
r = result[0]
|
|
189
|
+
i = result[1]
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/** @type {<T, R>(s: seqOp.ExclusiveScan<T, R>) => (input: Sequence<T>) => R} */
|
|
194
|
+
const reduce = ([first, s]) => input => last(first)(scan(s)(input))
|
|
195
|
+
|
|
196
|
+
/** @type {<T, R>(ro: op.ReduceOperator<R, T>) => (first: R) => (input: Sequence<T>) => R} */
|
|
197
|
+
const fold = ro => first => reduce(seqOp.exclusiveScan(ro)(first))
|
|
198
|
+
|
|
199
|
+
const entries = scan(seqOp.entries)
|
|
200
|
+
|
|
201
|
+
const sum = reduce(seqOp.sum)
|
|
202
|
+
|
|
203
|
+
const length = reduce(seqOp.length)
|
|
204
|
+
|
|
205
|
+
const join = pipe(seqOp.join)(reduce)
|
|
206
|
+
|
|
207
|
+
/** @type {<T>(f: (value: T) => boolean) => SequenceMap<T, T>} */
|
|
208
|
+
const takeWhile = f => input => () => {
|
|
209
|
+
const result = next(input)
|
|
210
|
+
if (result === undefined || !f(result[0])) { return undefined }
|
|
211
|
+
return result
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/** @type {(n: number) => <T>(input: Sequence<T>) => Sequence<T>} */
|
|
215
|
+
const drop = n => input => () => {
|
|
216
|
+
let iN = n
|
|
217
|
+
let iInput = input
|
|
218
|
+
while (true) {
|
|
219
|
+
const result = next(iInput)
|
|
220
|
+
if (iN <= 0 || result === undefined) { return result }
|
|
221
|
+
iN = iN - 1
|
|
222
|
+
iInput = result[1]
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/** @type {(n: number) => <T>(input: Sequence<T>) => T|undefined} */
|
|
227
|
+
const at = n => input => first(drop(n)(input))
|
|
228
|
+
|
|
229
|
+
/** @type {<T>(f: (value: T) => boolean) => SequenceReduce<T, T|undefined>} */
|
|
230
|
+
const find = f => input => first(filter(f)(input))
|
|
231
|
+
|
|
232
|
+
/** @type {<T>(f: (value: T) => boolean) => SequenceReduce<T, boolean>} */
|
|
233
|
+
const some = f => input => find(x => x)(map(f)(input)) !== undefined
|
|
71
234
|
|
|
72
|
-
/** @type {<T
|
|
73
|
-
const
|
|
235
|
+
/** @type {<T>(value: T) => SequenceReduce<T, boolean>} */
|
|
236
|
+
const includes = value => some(strictEqual(value))
|
|
237
|
+
|
|
238
|
+
/** @type {<T>(f: (value: T) => boolean) => SequenceReduce<T, boolean>} */
|
|
239
|
+
const every = f => input => !some(pipe(f)(logicalNot))(input)
|
|
240
|
+
|
|
241
|
+
/** @type {<T>(list: Sequence<T>) => Iterable<T>} */
|
|
242
|
+
const iterable = list => ({
|
|
243
|
+
*[Symbol.iterator]() {
|
|
244
|
+
let i = list
|
|
245
|
+
while (true) {
|
|
246
|
+
const result = next(i)
|
|
247
|
+
if (result === undefined) { return }
|
|
248
|
+
yield result[0]
|
|
249
|
+
i = result[1]
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
})
|
|
253
|
+
|
|
254
|
+
/** @type {<T>(list: Sequence<T>) => AsyncIterable<T>} */
|
|
255
|
+
const asyncIterable = list => ({
|
|
256
|
+
async *[Symbol.asyncIterator]() {
|
|
257
|
+
let i = list
|
|
258
|
+
while (true) {
|
|
259
|
+
const result = next(i)
|
|
260
|
+
if (result === undefined) { return }
|
|
261
|
+
yield result[0]
|
|
262
|
+
i = result[1]
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
})
|
|
266
|
+
|
|
267
|
+
/** @type {<A>(a: Sequence<A>) => <B>(b: Sequence<B>) => Sequence<array.Tuple2<A, B>>} */
|
|
268
|
+
const zip = a => b => () => {
|
|
269
|
+
const resultA = next(a)
|
|
270
|
+
if (resultA === undefined) { return undefined }
|
|
271
|
+
const resultB = next(b)
|
|
272
|
+
if (resultB === undefined) { return undefined }
|
|
273
|
+
return [[resultA[0], resultB[0]], zip(resultA[1])(resultB[1])]
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/** @type {<T>(list: Sequence<T>) => readonly T[]} */
|
|
277
|
+
const toArray = input => Array.from(iterable(input))
|
|
74
278
|
|
|
75
279
|
module.exports = {
|
|
76
280
|
/** @readonly */
|
|
77
|
-
|
|
281
|
+
next,
|
|
282
|
+
/** @readonly */
|
|
283
|
+
list,
|
|
284
|
+
/** @readonly */
|
|
285
|
+
empty,
|
|
286
|
+
/** @readonly */
|
|
287
|
+
at,
|
|
288
|
+
/** @readonly */
|
|
289
|
+
concat,
|
|
290
|
+
/** @readonly */
|
|
291
|
+
generate,
|
|
292
|
+
/** @readonly */
|
|
293
|
+
first,
|
|
294
|
+
/** @readonly */
|
|
295
|
+
fromArray,
|
|
296
|
+
/** @readonly */
|
|
297
|
+
toArray,
|
|
298
|
+
/** @readonly */
|
|
299
|
+
iterable,
|
|
300
|
+
/** @readonly */
|
|
301
|
+
asyncIterable,
|
|
302
|
+
/** @readonly */
|
|
303
|
+
flatMap,
|
|
304
|
+
/** @readonly */
|
|
305
|
+
flat,
|
|
306
|
+
/** @readonly */
|
|
307
|
+
map,
|
|
308
|
+
/** @readonly */
|
|
309
|
+
filter,
|
|
310
|
+
/** @readonly */
|
|
311
|
+
filterMap,
|
|
78
312
|
/** @readonly */
|
|
79
313
|
scan,
|
|
80
314
|
/** @readonly */
|
|
81
|
-
|
|
315
|
+
exclusiveScan,
|
|
316
|
+
/** @readonly */
|
|
317
|
+
last,
|
|
318
|
+
/** @readonly */
|
|
319
|
+
fold,
|
|
320
|
+
/** @readonly */
|
|
321
|
+
reduce,
|
|
322
|
+
/** @readonly */
|
|
323
|
+
entries,
|
|
82
324
|
/** @readonly */
|
|
83
325
|
sum,
|
|
84
326
|
/** @readonly */
|
|
327
|
+
join,
|
|
328
|
+
/** @readonly */
|
|
85
329
|
length,
|
|
86
330
|
/** @readonly */
|
|
87
|
-
|
|
331
|
+
drop,
|
|
88
332
|
/** @readonly */
|
|
89
|
-
|
|
333
|
+
find,
|
|
90
334
|
/** @readonly */
|
|
91
|
-
|
|
92
|
-
|
|
335
|
+
takeWhile,
|
|
336
|
+
/** @readonly */
|
|
337
|
+
some,
|
|
338
|
+
/** @readonly */
|
|
339
|
+
every,
|
|
340
|
+
/** @readonly */
|
|
341
|
+
includes,
|
|
342
|
+
/** @readonly */
|
|
343
|
+
zip,
|
|
344
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
const op = require('../../function/operator')
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @template T0
|
|
5
|
+
* @template T1
|
|
6
|
+
* @typedef {import('../array').Tuple2<T0, T1>} Tuple2
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @template T
|
|
11
|
+
* @template R
|
|
12
|
+
* @typedef {Tuple2<R, Scan<T, R>>} ScanResult
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @template T
|
|
17
|
+
* @template R
|
|
18
|
+
* @typedef {(value: T) => ScanResult<T, R>} Scan
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @template T
|
|
23
|
+
* @template R
|
|
24
|
+
* @typedef {Tuple2<R, Scan<T, R>>} ExclusiveScan
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
/** @type {<R, T>(operator: op.ReduceOperator<R, T>) => (prior: R) => Scan<T, R>} */
|
|
28
|
+
const scan = operator => {
|
|
29
|
+
/** @typedef {typeof operator extends op.ReduceOperator<infer R, infer T> ? [R, T] : never} RT */
|
|
30
|
+
/** @typedef {RT[0]} R */
|
|
31
|
+
/** @typedef {RT[1]} T */
|
|
32
|
+
/** @type {(prior: R) => Scan<T, R>} */
|
|
33
|
+
const f = prior => value => {
|
|
34
|
+
const result = operator(prior)(value)
|
|
35
|
+
return [result, f(result)]
|
|
36
|
+
}
|
|
37
|
+
return f
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** @type {<R, T>(operator: op.ReduceOperator<R, T>) => (first: R) => ExclusiveScan<T, R>} */
|
|
41
|
+
const exclusiveScan = operator => first => [first, scan(operator)(first)]
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @template T
|
|
45
|
+
* @typedef {Tuple2<number, T>} Entry
|
|
46
|
+
*/
|
|
47
|
+
|
|
48
|
+
/** @type {(index: number) => <T>(value: T) => ScanResult<T, Entry<T>>} */
|
|
49
|
+
const createEntries = index => value => [[index, value], createEntries(index + 1)]
|
|
50
|
+
|
|
51
|
+
const entries = createEntries(0)
|
|
52
|
+
|
|
53
|
+
/** @type {(separator: string) => ExclusiveScan<string, string>} */
|
|
54
|
+
const join = separator => ['', value => [value, scan(op.join(separator))(value)]]
|
|
55
|
+
|
|
56
|
+
const sum = exclusiveScan(op.addition)(0)
|
|
57
|
+
|
|
58
|
+
/** @type {(a: number) => () => number} */
|
|
59
|
+
const counter = a => () => a + 1
|
|
60
|
+
|
|
61
|
+
const length = exclusiveScan(counter)(0)
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* @template T
|
|
65
|
+
* @template R
|
|
66
|
+
* @typedef {(value: T) => R} Func
|
|
67
|
+
*/
|
|
68
|
+
|
|
69
|
+
/** @type {<T, R, X>(flatMap: (f: Func<T, readonly[R]>) => X) => (f: Func<T, R>) =>X} */
|
|
70
|
+
const map = flatMap => f => flatMap(x => [f(x)])
|
|
71
|
+
|
|
72
|
+
/** @type {<T, X>(flatMap: (f: Func<T, readonly[T]|[]>) => X) => (f: Func<T, boolean>) =>X} */
|
|
73
|
+
const filter = flatMap => f => flatMap(x => f(x) ? [x] : [])
|
|
74
|
+
|
|
75
|
+
module.exports = {
|
|
76
|
+
/** @readonly */
|
|
77
|
+
exclusiveScan,
|
|
78
|
+
/** @readonly */
|
|
79
|
+
scan,
|
|
80
|
+
/** @readonly */
|
|
81
|
+
join,
|
|
82
|
+
/** @readonly */
|
|
83
|
+
sum,
|
|
84
|
+
/** @readonly */
|
|
85
|
+
length,
|
|
86
|
+
/** @readonly */
|
|
87
|
+
entries,
|
|
88
|
+
/** @readonly */
|
|
89
|
+
map,
|
|
90
|
+
/** @readonly */
|
|
91
|
+
filter,
|
|
92
|
+
}
|
package/sequence/test.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
const seq = require('.')
|
|
2
|
+
const { sum } = require('./operator')
|
|
3
|
+
const op = require('./operator')
|
|
4
|
+
|
|
5
|
+
/** @type {<T>(input: seq.Sequence<T>) => void} */
|
|
6
|
+
const print = input => {
|
|
7
|
+
let i = input
|
|
8
|
+
while (true) {
|
|
9
|
+
const result = seq.next(i)
|
|
10
|
+
if (result === undefined) { return }
|
|
11
|
+
console.log(result[0])
|
|
12
|
+
i = result[1]
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
{
|
|
17
|
+
const big = seq.fromArray([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 42, 60])
|
|
18
|
+
const list0 = seq.fromArray([0, 1, 2, 3])
|
|
19
|
+
const list1 = seq.flatMap(x => seq.fromArray([x, x * 2, x * 3]))(list0)
|
|
20
|
+
const list2 = seq.concat(list0, list0)
|
|
21
|
+
const list3 = seq.exclusiveScan(sum)(list0)
|
|
22
|
+
const r = seq.find(x => x === 42)(big)
|
|
23
|
+
if (seq.every(x => x > 0)(big) !== true) { throw 'x'}
|
|
24
|
+
if (seq.every(x => x < 20)(big) !== false) { throw 'x' }
|
|
25
|
+
if (seq.some(x => x > 100)(big) !== false) { throw 'x' }
|
|
26
|
+
if (seq.some(x => x > 50)(big) !== true) { throw 'x' }
|
|
27
|
+
if (seq.first(seq.drop(16)(big)) !== 42) { throw 'drop'}
|
|
28
|
+
{
|
|
29
|
+
const a = seq.toArray(seq.generate(1_000_000))
|
|
30
|
+
let x = seq.concat(seq.fromArray(a), big)
|
|
31
|
+
const r = seq.next(x)
|
|
32
|
+
// print(x)
|
|
33
|
+
}
|
|
34
|
+
{
|
|
35
|
+
const a = seq.map(seq.generate)(seq.generate(100_000))
|
|
36
|
+
const array = seq.toArray(a)
|
|
37
|
+
const x = seq.concat(...array)
|
|
38
|
+
const r = seq.next(x)
|
|
39
|
+
// print(x)
|
|
40
|
+
}
|
|
41
|
+
{
|
|
42
|
+
let x = big
|
|
43
|
+
for (let i = 0; i < 1_000_000; ++i) {
|
|
44
|
+
x = seq.concat(seq.empty, x)
|
|
45
|
+
}
|
|
46
|
+
const r = seq.next(x)
|
|
47
|
+
// print(x)
|
|
48
|
+
}
|
|
49
|
+
{
|
|
50
|
+
let x = big
|
|
51
|
+
for (let i = 0; i < 1_000_000; ++i) {
|
|
52
|
+
x = seq.concat(x, seq.list(i))
|
|
53
|
+
}
|
|
54
|
+
const r = seq.next(x)
|
|
55
|
+
// print(x)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
{
|
|
60
|
+
const x = seq.join(':')(seq.fromArray(["1", "2", "3", "4", "5", "6"]))
|
|
61
|
+
if (x !== "1:2:3:4:5:6") { throw x }
|
|
62
|
+
}
|
package/test.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
const i = require('./')
|
|
2
2
|
|
|
3
|
-
require('./sequence/
|
|
3
|
+
require('./sequence/test')
|
|
4
4
|
require('./btree/test')
|
|
5
5
|
require('./sequence/iterable/test')
|
|
6
6
|
require('./sequence/asyncIterable/test')
|
|
7
7
|
require('./module-manager/test')
|
|
8
|
+
require('./json/test')
|
|
8
9
|
|
|
9
10
|
/** @type {() => never} */
|
|
10
11
|
const assert = () => { throw 'assert' }
|
package/sequence/list/index.js
DELETED
|
@@ -1,305 +0,0 @@
|
|
|
1
|
-
const array = require('../array')
|
|
2
|
-
const base = require('..')
|
|
3
|
-
const { pipe } = require('../../function')
|
|
4
|
-
const { logicalNot, strictEqual } = require('../../function/operator')
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* @template T
|
|
8
|
-
* @typedef {() => Result<T>} ListFunc
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* @template T
|
|
13
|
-
* @typedef {readonly [List<T>, List<T>]} Concat
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Use `next` function to get `first` and `tail` of the list.
|
|
18
|
-
*
|
|
19
|
-
* Please note that the list also contains `Concat<T>. We need this as
|
|
20
|
-
* a workaround because modern JavaScript implementations don't support
|
|
21
|
-
* ES6 TCO (Tail Call Optimization). Without this wotkaround we may have
|
|
22
|
-
* a stack overflow if a list contains a lot of concateneted lists.
|
|
23
|
-
*
|
|
24
|
-
* @template T
|
|
25
|
-
* @typedef { ListFunc<T> | Concat<T>} List
|
|
26
|
-
*/
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* @template T
|
|
30
|
-
* @typedef {FirstAndTail<T>|undefined} Result<T>
|
|
31
|
-
*/
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* @template T
|
|
35
|
-
* @typedef {array.Tuple2<T, List<T>>} FirstAndTail
|
|
36
|
-
*/
|
|
37
|
-
|
|
38
|
-
const empty = () => undefined
|
|
39
|
-
|
|
40
|
-
/** @type {<F, T>(a: readonly[F, List<T>]) => (b: List<T>) => readonly[F, List<T>]} */
|
|
41
|
-
const norm = ([a0, a1]) => b => [a0, [a1, b]]
|
|
42
|
-
|
|
43
|
-
/** @type {<T>(list: List<T>) => Result<T>} */
|
|
44
|
-
const next = list => {
|
|
45
|
-
let i = list
|
|
46
|
-
while (true) {
|
|
47
|
-
if (typeof i === 'function') { return i() }
|
|
48
|
-
const [a, b] = i
|
|
49
|
-
if (typeof a === 'function') {
|
|
50
|
-
const result = a()
|
|
51
|
-
if (result !== undefined) {
|
|
52
|
-
return norm(result)(b)
|
|
53
|
-
}
|
|
54
|
-
i = b
|
|
55
|
-
} else {
|
|
56
|
-
i = norm(a)(b)
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/** @type {<T>(list: List<T>) => T|undefined} */
|
|
62
|
-
const first = list => {
|
|
63
|
-
const result = next(list)
|
|
64
|
-
if (result === undefined) { return undefined }
|
|
65
|
-
return result[0]
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* @template T
|
|
70
|
-
* @template R
|
|
71
|
-
* @typedef {(list: List<T>) => List<R>} ListMap
|
|
72
|
-
*/
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* @template T
|
|
76
|
-
* @template R
|
|
77
|
-
* @typedef {(list: List<T>) => R} ListReduce
|
|
78
|
-
*/
|
|
79
|
-
|
|
80
|
-
/** @type {<T>(first: T) => List<T>} */
|
|
81
|
-
const one = first => () => [first, empty]
|
|
82
|
-
|
|
83
|
-
/** @type {<T>(array: array.Array<T>) => List<T>} */
|
|
84
|
-
const fromArray = a => {
|
|
85
|
-
/** @typedef {typeof a extends array.Array<infer T> ? T : never} T */
|
|
86
|
-
/** @type {(index: number) => List<T>} */
|
|
87
|
-
const at = index => () => {
|
|
88
|
-
const result = array.at(index)(a)
|
|
89
|
-
if (result === undefined) { return undefined }
|
|
90
|
-
return [result[0], at(index + 1)]
|
|
91
|
-
}
|
|
92
|
-
return at(0)
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/** @type {<T>(list0: List<T>) => ListMap<T, T>} */
|
|
96
|
-
const concat = a => b => [a, b]
|
|
97
|
-
|
|
98
|
-
/** @type {<T, R>(f: (value: T) => List<R>) => ListMap<T, R>} */
|
|
99
|
-
const flatMap = f => input => () => {
|
|
100
|
-
let i = input
|
|
101
|
-
while (true) {
|
|
102
|
-
const result = next(i)
|
|
103
|
-
if (result === undefined) { return undefined }
|
|
104
|
-
const [first, tail] = result
|
|
105
|
-
const firstResult = next(f(first))
|
|
106
|
-
if (firstResult !== undefined) {
|
|
107
|
-
const [firstFirst, firstTail] = firstResult
|
|
108
|
-
return [firstFirst, concat(firstTail)(flatMap(f)(tail))]
|
|
109
|
-
}
|
|
110
|
-
i = tail
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/** @type {<T>(list: List<List<T>>) => List<T>} */
|
|
115
|
-
const flat = flatMap(i => i)
|
|
116
|
-
|
|
117
|
-
/** @type {<T, R>(f: (value: T) => R) => ListMap<T, R>} */
|
|
118
|
-
const map = f => flatMap(i => one(f(i)))
|
|
119
|
-
|
|
120
|
-
/** @type {<T>(f: (value: T) => boolean) => ListMap<T, T>} */
|
|
121
|
-
const filter = f => flatMap(i => f(i) ? one(i) : empty)
|
|
122
|
-
|
|
123
|
-
/** @type {<T, R>(f: (value: T) => R|undefined) => (value: T) => List<R>} */
|
|
124
|
-
const filterMapFunc = f => i => {
|
|
125
|
-
const result = f(i)
|
|
126
|
-
if (result === undefined) { return empty }
|
|
127
|
-
return one(result)
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/** @type {<T, R>(f: (value: T) => R|undefined) => ListMap<T, R>} */
|
|
131
|
-
const filterMap = f => flatMap(filterMapFunc(f))
|
|
132
|
-
|
|
133
|
-
/** @type {<T, R>(s: base.Scan<T, R>) => ListMap<T, R>} */
|
|
134
|
-
const scan = s => input => () => {
|
|
135
|
-
const result = next(input)
|
|
136
|
-
if (result === undefined) {
|
|
137
|
-
return result
|
|
138
|
-
}
|
|
139
|
-
const [first, tail] = result
|
|
140
|
-
const [newFirst, newS] = s(first)
|
|
141
|
-
return [newFirst, scan(newS)(tail)]
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/** @type {<T, R>(s: base.ExclusiveScan<T, R>) => ListMap<T, R>} */
|
|
145
|
-
const exclusiveScan = ([first, s]) => input => () => [first, scan(s)(input)]
|
|
146
|
-
|
|
147
|
-
/** @type {<T>(def: T) => (input: List<T>) => T} */
|
|
148
|
-
const last = def => input => {
|
|
149
|
-
let r = def
|
|
150
|
-
let i = input
|
|
151
|
-
while (true) {
|
|
152
|
-
const result = next(i)
|
|
153
|
-
if (result === undefined) {
|
|
154
|
-
return r
|
|
155
|
-
}
|
|
156
|
-
r = result[0]
|
|
157
|
-
i = result[1]
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/** @type {<T, R>(s: base.ExclusiveScan<T, R>) => (input: List<T>) => R} */
|
|
162
|
-
const reduce = ([first, s]) => input => last(first)(scan(s)(input))
|
|
163
|
-
|
|
164
|
-
const entries = scan(base.entries)
|
|
165
|
-
|
|
166
|
-
const sum = reduce(base.sum)
|
|
167
|
-
|
|
168
|
-
const length = reduce(base.length)
|
|
169
|
-
|
|
170
|
-
const join = pipe(base.join)(reduce)
|
|
171
|
-
|
|
172
|
-
/** @type {<T>(f: (value: T) => boolean) => ListMap<T, T>} */
|
|
173
|
-
const takeWhile = f => input => () => {
|
|
174
|
-
const result = next(input)
|
|
175
|
-
if (result === undefined || !f(result[0])) { return undefined }
|
|
176
|
-
return result
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/** @type {(n: number) => <T>(input: List<T>) => List<T>} */
|
|
180
|
-
const drop = n => input => () => {
|
|
181
|
-
let iN = n
|
|
182
|
-
let iInput = input
|
|
183
|
-
while (true) {
|
|
184
|
-
const result = next(iInput)
|
|
185
|
-
if (iN <= 0 || result === undefined) { return result }
|
|
186
|
-
iN = iN - 1
|
|
187
|
-
iInput = result[1]
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/** @type {(n: number) => <T>(input: List<T>) => T|undefined} */
|
|
192
|
-
const at = n => input => first(drop(n)(input))
|
|
193
|
-
|
|
194
|
-
/** @type {<T>(f: (value: T) => boolean) => ListReduce<T, T|undefined>} */
|
|
195
|
-
const find = f => input => first(filter(f)(input))
|
|
196
|
-
|
|
197
|
-
/** @type {<T>(f: (value: T) => boolean) => ListReduce<T, boolean>} */
|
|
198
|
-
const some = f => input => find(x => x)(map(f)(input)) !== undefined
|
|
199
|
-
|
|
200
|
-
/** @type {<T>(value: T) => ListReduce<T, boolean>} */
|
|
201
|
-
const includes = value => some(strictEqual(value))
|
|
202
|
-
|
|
203
|
-
/** @type {<T>(f: (value: T) => boolean) => ListReduce<T, boolean>} */
|
|
204
|
-
const every = f => input => !some(pipe(f)(logicalNot))(input)
|
|
205
|
-
|
|
206
|
-
/** @type {<T>(list: List<T>) => Iterable<T>} */
|
|
207
|
-
const iterable = list => ({
|
|
208
|
-
*[Symbol.iterator]() {
|
|
209
|
-
let i = list
|
|
210
|
-
while (true) {
|
|
211
|
-
const result = next(i)
|
|
212
|
-
if (result === undefined) { return }
|
|
213
|
-
yield result[0]
|
|
214
|
-
i = result[1]
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
})
|
|
218
|
-
|
|
219
|
-
/** @type {<T>(list: List<T>) => AsyncIterable<T>} */
|
|
220
|
-
const asyncIterable = list => ({
|
|
221
|
-
async *[Symbol.asyncIterator]() {
|
|
222
|
-
let i = list
|
|
223
|
-
while (true) {
|
|
224
|
-
const result = next(i)
|
|
225
|
-
if (result === undefined) { return }
|
|
226
|
-
yield result[0]
|
|
227
|
-
i = result[1]
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
})
|
|
231
|
-
|
|
232
|
-
/** @type {<A>(a: List<A>) => <B>(b: List<B>) => List<array.Tuple2<A, B>>} */
|
|
233
|
-
const zip = a => b => () => {
|
|
234
|
-
const resultA = next(a)
|
|
235
|
-
if (resultA === undefined) { return undefined }
|
|
236
|
-
const resultB = next(b)
|
|
237
|
-
if (resultB === undefined) { return undefined }
|
|
238
|
-
return [[resultA[0], resultB[0]], zip(resultA[1])(resultB[1])]
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
/** @type {<T>(list: List<T>) => readonly T[]} */
|
|
242
|
-
const toArray = input => Array.from(iterable(input))
|
|
243
|
-
|
|
244
|
-
module.exports = {
|
|
245
|
-
/** @readonly */
|
|
246
|
-
next,
|
|
247
|
-
/** @readonly */
|
|
248
|
-
one,
|
|
249
|
-
/** @readonly */
|
|
250
|
-
empty,
|
|
251
|
-
/** @readonly */
|
|
252
|
-
at,
|
|
253
|
-
/** @readonly */
|
|
254
|
-
concat,
|
|
255
|
-
/** @readonly */
|
|
256
|
-
first,
|
|
257
|
-
/** @readonly */
|
|
258
|
-
fromArray,
|
|
259
|
-
/** @readonly */
|
|
260
|
-
toArray,
|
|
261
|
-
/** @readonly */
|
|
262
|
-
iterable,
|
|
263
|
-
/** @readonly */
|
|
264
|
-
asyncIterable,
|
|
265
|
-
/** @readonly */
|
|
266
|
-
flatMap,
|
|
267
|
-
/** @readonly */
|
|
268
|
-
flat,
|
|
269
|
-
/** @readonly */
|
|
270
|
-
map,
|
|
271
|
-
/** @readonly */
|
|
272
|
-
filter,
|
|
273
|
-
/** @readonly */
|
|
274
|
-
filterMap,
|
|
275
|
-
/** @readonly */
|
|
276
|
-
scan,
|
|
277
|
-
/** @readonly */
|
|
278
|
-
exclusiveScan,
|
|
279
|
-
/** @readonly */
|
|
280
|
-
last,
|
|
281
|
-
/** @readonly */
|
|
282
|
-
reduce,
|
|
283
|
-
/** @readonly */
|
|
284
|
-
entries,
|
|
285
|
-
/** @readonly */
|
|
286
|
-
sum,
|
|
287
|
-
/** @readonly */
|
|
288
|
-
join,
|
|
289
|
-
/** @readonly */
|
|
290
|
-
length,
|
|
291
|
-
/** @readonly */
|
|
292
|
-
drop,
|
|
293
|
-
/** @readonly */
|
|
294
|
-
find,
|
|
295
|
-
/** @readonly */
|
|
296
|
-
takeWhile,
|
|
297
|
-
/** @readonly */
|
|
298
|
-
some,
|
|
299
|
-
/** @readonly */
|
|
300
|
-
every,
|
|
301
|
-
/** @readonly */
|
|
302
|
-
includes,
|
|
303
|
-
/** @readonly */
|
|
304
|
-
zip,
|
|
305
|
-
}
|
package/sequence/list/test.js
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
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 (true) {
|
|
8
|
-
const result = list.next(i)
|
|
9
|
-
if (result === undefined) { return }
|
|
10
|
-
// console.log(result[0])
|
|
11
|
-
i = result[1]
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
{
|
|
16
|
-
const big = list.fromArray([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 42, 60])
|
|
17
|
-
const list0 = list.fromArray([0, 1, 2, 3])
|
|
18
|
-
const list1 = list.flatMap(x => list.fromArray([x, x * 2, x * 3]))(list0)
|
|
19
|
-
const list2 = list.concat(list0)(list0)
|
|
20
|
-
const list3 = list.exclusiveScan(sum)(list0)
|
|
21
|
-
const r = list.find(x => x === 42)(big)
|
|
22
|
-
if (list.every(x => x > 0)(big) !== true) { throw 'x'}
|
|
23
|
-
if (list.every(x => x < 20)(big) !== false) { throw 'x' }
|
|
24
|
-
if (list.some(x => x > 100)(big) !== false) { throw 'x' }
|
|
25
|
-
if (list.some(x => x > 50)(big) !== true) { throw 'x' }
|
|
26
|
-
if (list.first(list.drop(16)(big)) !== 42) { throw 'drop'}
|
|
27
|
-
{
|
|
28
|
-
let x = big
|
|
29
|
-
for (let i = 0; i < 1_000_000; ++i) {
|
|
30
|
-
x = list.concat(list.empty)(x)
|
|
31
|
-
}
|
|
32
|
-
const r = list.next(x)
|
|
33
|
-
// print(x)
|
|
34
|
-
}
|
|
35
|
-
{
|
|
36
|
-
let x = big
|
|
37
|
-
for (let i = 0; i < 1_000_000; ++i) {
|
|
38
|
-
x = list.concat(x)(list.one(i))
|
|
39
|
-
}
|
|
40
|
-
const r = list.next(x)
|
|
41
|
-
// print(x)
|
|
42
|
-
}
|
|
43
|
-
}
|