functionalscript 0.0.241 → 0.0.242
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/commonjs/package/dependencies/index.js +1 -1
- package/commonjs/package/dependencies/test.js +0 -3
- package/commonjs/path/index.js +9 -9
- package/json/index.js +16 -16
- package/package.json +1 -1
- package/test.js +1 -1
- package/types/array/index.js +1 -1
- package/types/btree/index.js +2 -2
- package/types/btree/test.js +2 -2
- package/types/function/operator/index.js +51 -11
- package/types/list/index.js +372 -0
- package/types/{sequence → list}/test.js +32 -19
- package/types/map/index.js +4 -4
- package/types/map/test.js +1 -1
- package/types/object/index.js +2 -3
- package/types/sequence/README.md +0 -68
- package/types/sequence/index.js +0 -382
package/commonjs/path/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
const seq = require("../../types/
|
|
1
|
+
const seq = require("../../types/list")
|
|
2
2
|
const option = require("../../types/option")
|
|
3
3
|
const { compose } = require("../../types/function")
|
|
4
4
|
const dep = require("../package/dependencies")
|
|
5
5
|
const { at } = require("../../types/object")
|
|
6
|
-
const pack = require("../package")
|
|
6
|
+
// const pack = require("../package")
|
|
7
7
|
|
|
8
8
|
/** @typedef {readonly string[]} Items */
|
|
9
9
|
|
|
@@ -18,7 +18,7 @@ const pack = require("../package")
|
|
|
18
18
|
/** @type {(path: string) => readonly string[]} */
|
|
19
19
|
const split = path => path.split('/')
|
|
20
20
|
|
|
21
|
-
/** @type {(s: undefined|seq.
|
|
21
|
+
/** @type {(s: undefined|seq.List<string>) => (items: string) => undefined|seq.List<string>} */
|
|
22
22
|
const normItemsOp = prior => item => {
|
|
23
23
|
if (prior === undefined) { return undefined }
|
|
24
24
|
switch (item) {
|
|
@@ -29,17 +29,17 @@ const normItemsOp = prior => item => {
|
|
|
29
29
|
return result.tail
|
|
30
30
|
}
|
|
31
31
|
default: {
|
|
32
|
-
return seq.
|
|
32
|
+
return seq.nonEmpty(item)(prior)
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
/** @type {(items: seq.
|
|
37
|
+
/** @type {(items: seq.List<string>) => seq.List<string>|undefined} */
|
|
38
38
|
const normItems = compose(seq.reduce(normItemsOp)([]))(option.map(seq.reverse))
|
|
39
39
|
|
|
40
40
|
/** @type {(local: string) => (path: string) => LocalPath|undefined} */
|
|
41
41
|
const parseLocal = local => {
|
|
42
|
-
/** @type {(path: string) => readonly[boolean, seq.
|
|
42
|
+
/** @type {(path: string) => readonly[boolean, seq.List<string>]} */
|
|
43
43
|
const fSeq = path => {
|
|
44
44
|
const pathSeq = split(path)
|
|
45
45
|
switch (seq.first(undefined)(pathSeq)) {
|
|
@@ -61,9 +61,9 @@ const parseLocal = local => {
|
|
|
61
61
|
return f
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
/** @typedef {readonly[string, seq.
|
|
64
|
+
/** @typedef {readonly[string, seq.List<string>]} IdPath */
|
|
65
65
|
|
|
66
|
-
/** @type {(prior: readonly[string|undefined, seq.
|
|
66
|
+
/** @type {(prior: readonly[string|undefined, seq.List<string>]) => seq.Thunk<IdPath>} */
|
|
67
67
|
const variants = prior => () => {
|
|
68
68
|
const [a, b] = prior
|
|
69
69
|
const r = seq.next(b)
|
|
@@ -88,7 +88,7 @@ const mapDependency = d => ([external, internal]) => {
|
|
|
88
88
|
* }} Path
|
|
89
89
|
*/
|
|
90
90
|
|
|
91
|
-
/** @type {(d: dep.DependenciesJson) => (dir: boolean) => (items: seq.
|
|
91
|
+
/** @type {(d: dep.DependenciesJson) => (dir: boolean) => (items: seq.List<string>) => Path|undefined} */
|
|
92
92
|
const parseGlobal = d => dir => items => {
|
|
93
93
|
if (d === undefined) { return undefined }
|
|
94
94
|
const v = variants([undefined, items])
|
package/json/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
const seq = require('../types/
|
|
1
|
+
const seq = require('../types/list')
|
|
2
2
|
const object = require('../types/object')
|
|
3
3
|
const array = require('../types/array')
|
|
4
|
-
const
|
|
4
|
+
const op = require('../types/function/operator')
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* @typedef {{
|
|
@@ -13,9 +13,9 @@ const { todo } = require('../dev')
|
|
|
13
13
|
|
|
14
14
|
/** @typedef {Object|boolean|string|number|null|Array} Unknown */
|
|
15
15
|
|
|
16
|
-
/** @type {(value: Unknown) => (path: seq.
|
|
16
|
+
/** @type {(value: Unknown) => (path: seq.List<string>) => (src: Unknown|undefined) => Unknown} */
|
|
17
17
|
const setProperty = value => {
|
|
18
|
-
/** @type {(path: seq.
|
|
18
|
+
/** @type {(path: seq.List<string>) => (src: Unknown|undefined) => Unknown} */
|
|
19
19
|
const f = path => src => {
|
|
20
20
|
const result = seq.next(path)
|
|
21
21
|
if (result === undefined) { return value }
|
|
@@ -26,10 +26,10 @@ const setProperty = value => {
|
|
|
26
26
|
return f
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
/** @type {(_: string) => seq.
|
|
29
|
+
/** @type {(_: string) => seq.List<string>} */
|
|
30
30
|
const stringSerialize = input => [JSON.stringify(input)]
|
|
31
31
|
|
|
32
|
-
/** @type {(_: number) => seq.
|
|
32
|
+
/** @type {(_: number) => seq.List<string>} */
|
|
33
33
|
const numberSerialize = input => [JSON.stringify(input)]
|
|
34
34
|
|
|
35
35
|
const nullSerialize = ['null']
|
|
@@ -38,19 +38,19 @@ const trueSerialize = ['true']
|
|
|
38
38
|
|
|
39
39
|
const falseSerialize = ['false']
|
|
40
40
|
|
|
41
|
-
/** @type {(_: boolean) => seq.
|
|
41
|
+
/** @type {(_: boolean) => seq.List<string>} */
|
|
42
42
|
const boolSerialize = value => value ? trueSerialize : falseSerialize
|
|
43
43
|
|
|
44
44
|
const colon = [':']
|
|
45
45
|
const comma = [',']
|
|
46
46
|
|
|
47
|
-
/** @type {
|
|
47
|
+
/** @type {op.Fold<seq.List<string>>} */
|
|
48
48
|
const joinOp = a => b => seq.flat([a, comma, b])
|
|
49
49
|
|
|
50
|
-
/** @type {(input: seq.
|
|
50
|
+
/** @type {(input: seq.List<seq.List<string>>) => seq.List<string>} */
|
|
51
51
|
const join = seq.fold(joinOp)([])
|
|
52
52
|
|
|
53
|
-
/** @type {(open: string) => (close: string) => (input: seq.
|
|
53
|
+
/** @type {(open: string) => (close: string) => (input: seq.List<seq.List<string>>) => seq.List<string>} */
|
|
54
54
|
const list = open => close => {
|
|
55
55
|
const seqOpen = [open]
|
|
56
56
|
const seqClose = [close]
|
|
@@ -63,19 +63,19 @@ const arrayList = list('[')(']')
|
|
|
63
63
|
|
|
64
64
|
/** @typedef {object.Entry<Unknown>} Entry*/
|
|
65
65
|
|
|
66
|
-
/** @typedef {(seq.
|
|
66
|
+
/** @typedef {(seq.List<Entry>)} Entries */
|
|
67
67
|
|
|
68
68
|
/** @typedef {(entries: Entries) => Entries} MapEntries */
|
|
69
69
|
|
|
70
|
-
/** @type {(mapEntries: MapEntries) => (value: Unknown) => seq.
|
|
70
|
+
/** @type {(mapEntries: MapEntries) => (value: Unknown) => seq.List<string>} */
|
|
71
71
|
const serialize = sort => {
|
|
72
|
-
/** @type {(kv: readonly[string, Unknown]) => seq.
|
|
72
|
+
/** @type {(kv: readonly[string, Unknown]) => seq.List<string>} */
|
|
73
73
|
const propertySerialize = ([k, v]) => seq.flat([
|
|
74
74
|
stringSerialize(k),
|
|
75
75
|
colon,
|
|
76
76
|
f(v)
|
|
77
77
|
])
|
|
78
|
-
/** @type {(object: Object) => seq.
|
|
78
|
+
/** @type {(object: Object) => seq.List<string>} */
|
|
79
79
|
const objectSerialize = input => {
|
|
80
80
|
const entries = Object.entries(input)
|
|
81
81
|
const sortedEntries = sort(entries)
|
|
@@ -83,12 +83,12 @@ const serialize = sort => {
|
|
|
83
83
|
const serializedEntries = seq.map(propertySerialize)(sortedEntries)
|
|
84
84
|
return objectList(serializedEntries)
|
|
85
85
|
}
|
|
86
|
-
/** @type {(input: Array) => seq.
|
|
86
|
+
/** @type {(input: Array) => seq.List<string>} */
|
|
87
87
|
const arraySerialize = input => {
|
|
88
88
|
const serializedEntries = seq.map(f)(input)
|
|
89
89
|
return arrayList(serializedEntries)
|
|
90
90
|
}
|
|
91
|
-
/** @type {(value: Unknown) => seq.
|
|
91
|
+
/** @type {(value: Unknown) => seq.List < string >} */
|
|
92
92
|
const f = value => {
|
|
93
93
|
switch (typeof value) {
|
|
94
94
|
case 'boolean': { return boolSerialize(value) }
|
package/package.json
CHANGED
package/test.js
CHANGED
package/types/array/index.js
CHANGED
package/types/btree/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const cmp = require('../function/compare')
|
|
2
2
|
const { index3, index5 } = cmp
|
|
3
|
-
const seq = require('../
|
|
3
|
+
const seq = require('../list')
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @template T
|
|
@@ -303,7 +303,7 @@ const replaceVisitor = {
|
|
|
303
303
|
notFound: notFoundGet,
|
|
304
304
|
}
|
|
305
305
|
|
|
306
|
-
/** @type {<T>(node: Node<T>) => seq.
|
|
306
|
+
/** @type {<T>(node: Node<T>) => seq.List<T>} */
|
|
307
307
|
const values = node => () => {
|
|
308
308
|
const f = () => {
|
|
309
309
|
switch (node.length) {
|
package/types/btree/test.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const btree = require('.')
|
|
2
2
|
const { setVisitor, values } = btree
|
|
3
3
|
const { cmp } = require('../function/compare')
|
|
4
|
-
const list = require('../
|
|
4
|
+
const list = require('../list')
|
|
5
5
|
|
|
6
6
|
/** @type {(node: btree.Node<string>) => (value: string) => btree.Node<string>} */
|
|
7
7
|
const set = node => value => {
|
|
@@ -22,7 +22,7 @@ const test = () => {
|
|
|
22
22
|
_map = set(_map)('f')
|
|
23
23
|
//
|
|
24
24
|
{
|
|
25
|
-
/** @type {
|
|
25
|
+
/** @type {list.Result<string>} */
|
|
26
26
|
let _item = list.next(values(_map))
|
|
27
27
|
while (_item !== undefined) {
|
|
28
28
|
_item = list.next(_item.tail)
|
|
@@ -2,44 +2,76 @@
|
|
|
2
2
|
* @template A
|
|
3
3
|
* @template B
|
|
4
4
|
* @template R
|
|
5
|
-
* @typedef {(a: A) => (b: B) => R}
|
|
5
|
+
* @typedef {(a: A) => (b: B) => R} Binary
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
* @template
|
|
10
|
-
* @
|
|
11
|
-
* @typedef {BinaryOperator<R, T, R>} ReduceOperator
|
|
9
|
+
* @template I,O
|
|
10
|
+
* @typedef {Binary<O, I, O>} Reduce
|
|
12
11
|
*/
|
|
13
12
|
|
|
14
|
-
/** @type {(separator: string) =>
|
|
13
|
+
/** @type {(separator: string) => Fold<string>} */
|
|
15
14
|
const join = separator => prior => value => `${prior}${separator}${value}`
|
|
16
15
|
|
|
17
|
-
/** @type {
|
|
16
|
+
/** @type {Fold<number>} */
|
|
18
17
|
const addition = a => b => a + b
|
|
19
18
|
|
|
20
19
|
/**
|
|
21
20
|
* @template T
|
|
22
21
|
* @template R
|
|
23
|
-
* @typedef {(value: T) => R}
|
|
22
|
+
* @typedef {(value: T) => R} Unary
|
|
24
23
|
*/
|
|
25
24
|
|
|
26
|
-
/** @type {
|
|
25
|
+
/** @type {Unary<boolean, boolean>} */
|
|
27
26
|
const logicalNot = v => !v
|
|
28
27
|
|
|
29
28
|
/**
|
|
30
29
|
* @template T
|
|
31
|
-
* @typedef {
|
|
30
|
+
* @typedef {Binary<T, T, boolean>} Equal
|
|
32
31
|
*/
|
|
33
32
|
|
|
34
33
|
/** @type {<T>(a: T) => (b: T) => boolean} */
|
|
35
34
|
const strictEqual = a => b => a === b
|
|
36
35
|
|
|
37
|
-
/** @type {
|
|
36
|
+
/** @type {Fold<number>} */
|
|
38
37
|
const min = a => b => a < b ? a : b
|
|
39
38
|
|
|
40
|
-
/** @type {
|
|
39
|
+
/** @type {Fold<number>} */
|
|
41
40
|
const max = a => b => a > b ? a : b
|
|
42
41
|
|
|
42
|
+
/**
|
|
43
|
+
* @template I,O
|
|
44
|
+
* @typedef {(input: I) => readonly[O, Scan<I,O>]} Scan
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @template I,S,O
|
|
49
|
+
* @typedef {(prior: S) => (input: I) => readonly[O, S]} StateScan
|
|
50
|
+
*/
|
|
51
|
+
|
|
52
|
+
/** @type {<I, S, O>(op: StateScan<I, S, O>) => (prior: S) => Scan<I, O>} */
|
|
53
|
+
const stateScanToScan = op => prior => i => {
|
|
54
|
+
const [o, s] = op(prior)(i)
|
|
55
|
+
return [o, stateScanToScan(op)(s)]
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** @type {<I, O>(reduce: Reduce<I, O>) => (prior: O) => Scan<I, O>} */
|
|
59
|
+
const reduceToScan = reduce => prior => i => {
|
|
60
|
+
const result = reduce(prior)(i)
|
|
61
|
+
return [result, reduceToScan(reduce)(result)]
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* @template T
|
|
66
|
+
* @typedef {Reduce<T, T>} Fold
|
|
67
|
+
*/
|
|
68
|
+
|
|
69
|
+
/** @type {<T>(fold: Fold<T>) => Scan<T, T>} */
|
|
70
|
+
const foldToScan = op => init => [init, reduceToScan(op)(init)]
|
|
71
|
+
|
|
72
|
+
/** @type {(a: number) => () => number} */
|
|
73
|
+
const counter = a => () => a + 1
|
|
74
|
+
|
|
43
75
|
module.exports = {
|
|
44
76
|
/** @readonly */
|
|
45
77
|
join,
|
|
@@ -53,4 +85,12 @@ module.exports = {
|
|
|
53
85
|
min,
|
|
54
86
|
/** @readonly */
|
|
55
87
|
max,
|
|
88
|
+
/** @readonly */
|
|
89
|
+
stateScanToScan,
|
|
90
|
+
/** @readonly */
|
|
91
|
+
reduceToScan,
|
|
92
|
+
/** @readonly */
|
|
93
|
+
foldToScan,
|
|
94
|
+
/** @readonly */
|
|
95
|
+
counter,
|
|
56
96
|
}
|
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
const { compose, identity } = require('../function')
|
|
2
|
+
const operator = require('../function/operator')
|
|
3
|
+
const { logicalNot, strictEqual, stateScanToScan, reduceToScan, foldToScan } = require('../function/operator')
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @template T
|
|
7
|
+
* @typedef {NotLazy<T> | Thunk<T>} List
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @template T
|
|
12
|
+
* @typedef {|
|
|
13
|
+
* Result<T> |
|
|
14
|
+
* Concat<T> |
|
|
15
|
+
* readonly T[]
|
|
16
|
+
* } NotLazy
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @template T
|
|
21
|
+
* @typedef {undefined | NonEmpty<T>} Result
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @template T
|
|
26
|
+
* @typedef {() => List<T>} Thunk
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @template T
|
|
31
|
+
* @typedef {{
|
|
32
|
+
* readonly isConcat?: undefined
|
|
33
|
+
* readonly first: T
|
|
34
|
+
* readonly tail: List<T>
|
|
35
|
+
* }} NonEmpty
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @template T
|
|
40
|
+
* @typedef {{
|
|
41
|
+
* readonly isConcat: true
|
|
42
|
+
* readonly a: List<T>
|
|
43
|
+
* readonly b: List<T>
|
|
44
|
+
* }} Concat
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
/** @type {<T>(first: T) => (tail: List<T>) => NonEmpty<T>} */
|
|
48
|
+
const nonEmpty = first => tail => ({ first, tail })
|
|
49
|
+
|
|
50
|
+
/** @type {(i: number) => <T>(array: readonly T[]) => Result<T>} */
|
|
51
|
+
const fromArrayAt = i => array => i < array.length ? nonEmpty(array[i])(() => fromArrayAt(i + 1)(array)) : undefined
|
|
52
|
+
|
|
53
|
+
/** @type {<T>(array: readonly T[]) => Result<T>} */
|
|
54
|
+
const fromArray = fromArrayAt(0)
|
|
55
|
+
|
|
56
|
+
/** @type {<T>(a: List<T>) => (b: List<T>) => List<T>} */
|
|
57
|
+
const concat = a => b => b === undefined ? a : ({ isConcat: true, a, b })
|
|
58
|
+
|
|
59
|
+
/** @type {<T>(list: List<T>) => NotLazy<T> } */
|
|
60
|
+
const trampoline = list => {
|
|
61
|
+
let i = list
|
|
62
|
+
while (typeof i === 'function') { i = i() }
|
|
63
|
+
return i
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** @type {<T>(list: List<T>) => Result<T>} */
|
|
67
|
+
const next = list => {
|
|
68
|
+
/** @type {readonly[typeof list, typeof list]} */
|
|
69
|
+
let [a, b] = [list, undefined]
|
|
70
|
+
while (true) {
|
|
71
|
+
a = trampoline(a)
|
|
72
|
+
|
|
73
|
+
if (a instanceof Array) {
|
|
74
|
+
a = fromArray(a)
|
|
75
|
+
} else if (a?.isConcat) {
|
|
76
|
+
[a, b] = [a.a, concat(a.b)(b)]
|
|
77
|
+
continue
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (a !== undefined) {
|
|
81
|
+
return nonEmpty(a.first)(concat(a.tail)(b))
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (b === undefined) { return undefined }
|
|
85
|
+
|
|
86
|
+
[a, b] = [b, undefined]
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** @type {<T>(list: List<T>) => Iterable<T>} */
|
|
91
|
+
const iterable = list => ({
|
|
92
|
+
*[Symbol.iterator]() {
|
|
93
|
+
let i = list
|
|
94
|
+
while (true) {
|
|
95
|
+
const r = next(i)
|
|
96
|
+
if (r === undefined) { return }
|
|
97
|
+
yield r.first
|
|
98
|
+
i = r.tail
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
/** @type {<T>(list: List<T>) => readonly T[]} */
|
|
104
|
+
const toArray = list => {
|
|
105
|
+
const u = trampoline(list)
|
|
106
|
+
return u instanceof Array ? u : Array.from(iterable(u))
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** @type {<I, O>(step: (n: NonEmpty<I>) => List<O>) => (input: List<I>) => List<O>} */
|
|
110
|
+
const apply = f => input => () => {
|
|
111
|
+
const n = next(input)
|
|
112
|
+
if (n === undefined) { return undefined }
|
|
113
|
+
return f(n)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** @type {<T>(n: NonEmpty<List<T>>) => List<T>} */
|
|
117
|
+
const flatStep = n => concat(n.first)(flat(n.tail))
|
|
118
|
+
|
|
119
|
+
/** @type {<T>(list: List<List<T>>) => List<T>} */
|
|
120
|
+
const flat = apply(flatStep)
|
|
121
|
+
|
|
122
|
+
/** @type {<I, O>(f: (value: I) => O) => (n: NonEmpty<I>) => List<O>} */
|
|
123
|
+
const mapStep = f => n => nonEmpty(f(n.first))(map(f)(n.tail))
|
|
124
|
+
|
|
125
|
+
/** @type {<I, O>(f: (value: I) => O) => (input: List<I>) => List<O>} */
|
|
126
|
+
const map = f => apply(mapStep(f))
|
|
127
|
+
|
|
128
|
+
/** @type {<I, O>(f: (value: I) => List<O>) => (input: List<I>) => List<O>} */
|
|
129
|
+
const flatMap = f => compose(map(f))(flat)
|
|
130
|
+
|
|
131
|
+
/** @type {<T>(f: (value: T) => boolean) => (n: NonEmpty<T>) => List<T>} */
|
|
132
|
+
const filterStep = f => n => {
|
|
133
|
+
const tail = filter(f)(n.tail)
|
|
134
|
+
return f(n.first) ? nonEmpty(n.first)(tail) : tail
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** @type {<T>(f: (value: T) => boolean) => (input: List<T>) => List<T>} */
|
|
138
|
+
const filter = f => apply(filterStep(f))
|
|
139
|
+
|
|
140
|
+
/** @type {<I, O>(f: (value: I) => O|undefined) => (n: NonEmpty<I>) => List<O>} */
|
|
141
|
+
const filterMapStep = f => n => {
|
|
142
|
+
const [first, tail] = [f(n.first), filterMap(f)(n.tail)]
|
|
143
|
+
return first === undefined ? tail : nonEmpty(first)(tail)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** @type {<I, O>(f: (value: I) => O|undefined) => (input: List<I>) => List<O>} */
|
|
147
|
+
const filterMap = f => apply(filterMapStep(f))
|
|
148
|
+
|
|
149
|
+
/** @type {<T>(f: (value: T) => boolean) => (n: NonEmpty<T>) => List<T>} */
|
|
150
|
+
const takeWhileStep = f => n => f(n.first) ? nonEmpty(n.first)(takeWhile(f)(n.tail)) : undefined
|
|
151
|
+
|
|
152
|
+
/** @type {<T>(f: (value: T) => boolean) => (input: List<T>) => List<T>} */
|
|
153
|
+
const takeWhile = f => apply(takeWhileStep(f))
|
|
154
|
+
|
|
155
|
+
/** @type {(n: number) => <T>(result: NonEmpty<T>) => List<T>} */
|
|
156
|
+
const takeStep = n => ne => 0 < n ? nonEmpty(ne.first)(take(n - 1)(ne.tail)) : undefined
|
|
157
|
+
|
|
158
|
+
/** @type {(n: number) => <T>(input: List<T>) => List<T>} */
|
|
159
|
+
const take = n => apply(takeStep(n))
|
|
160
|
+
|
|
161
|
+
/** @type {<T>(f: (value: T) => boolean) => (ne: NonEmpty<T>) => List<T>} */
|
|
162
|
+
const dropWhileStep = f => ne => f(ne.first) ? dropWhile(f)(ne.tail) : ne
|
|
163
|
+
|
|
164
|
+
/** @type {<T>(f: (value: T) => boolean) => (input: List<T>) => List<T>} */
|
|
165
|
+
const dropWhile = f => apply(dropWhileStep(f))
|
|
166
|
+
|
|
167
|
+
/** @type {(n: number) => <T>(ne: NonEmpty<T>) => List<T>} */
|
|
168
|
+
const dropStep = n => ne => 0 < n ? drop(n - 1)(ne.tail) : ne
|
|
169
|
+
|
|
170
|
+
/** @type {(n: number) => <T>(input: List<T>) => List<T>} */
|
|
171
|
+
const drop = n => apply(dropStep(n))
|
|
172
|
+
|
|
173
|
+
/** @type {<D>(def: D) => <T>(input: List<T>) => D|T} */
|
|
174
|
+
const first = def => input => {
|
|
175
|
+
const result = next(input)
|
|
176
|
+
if (result === undefined) { return def }
|
|
177
|
+
return result.first
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** @type {<D>(def: D) => <T>(input: List<T>) => D|T} */
|
|
181
|
+
const last = def => input => {
|
|
182
|
+
/** @typedef {typeof input extends List<infer T> ? T : never} T */
|
|
183
|
+
let i = nonEmpty(/** @type {(typeof def)|T} */(def))(input)
|
|
184
|
+
while (true) {
|
|
185
|
+
const result = next(i.tail)
|
|
186
|
+
if (result === undefined) {
|
|
187
|
+
return i.first
|
|
188
|
+
}
|
|
189
|
+
i = result
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/** @type {<D>(def: D) => <T>(f: (value: T) => boolean) => (input: List<T>) => D|T} */
|
|
194
|
+
const find = def => f => input => first(def)(filter(f)(input))
|
|
195
|
+
|
|
196
|
+
/** @type {(input: List<boolean>) => boolean} */
|
|
197
|
+
const some = input => find
|
|
198
|
+
(false)
|
|
199
|
+
(/** @type {(_: boolean) => boolean} */(identity))
|
|
200
|
+
(input)
|
|
201
|
+
|
|
202
|
+
/** @type {(input: List<boolean>) => boolean} */
|
|
203
|
+
const every = input => !some(map(logicalNot)(input))
|
|
204
|
+
|
|
205
|
+
/** @type {<T>(value: T) => (sequence: List<T>) => boolean} */
|
|
206
|
+
const includes = value => input => some(map(strictEqual(value))(input))
|
|
207
|
+
|
|
208
|
+
/** @type {(count: number) => Thunk<number>} */
|
|
209
|
+
const countdown = count => () => {
|
|
210
|
+
if (count <= 0) { return undefined }
|
|
211
|
+
const first = count - 1
|
|
212
|
+
return nonEmpty(first)(countdown(first))
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/** @type {<T>(list: List<T>) => List<T>} */
|
|
216
|
+
const cycle = list => () => {
|
|
217
|
+
const i = next(list)
|
|
218
|
+
return i === undefined ? undefined : nonEmpty(i.first)(concat(i.tail)(cycle(list)))
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/** @type {<I, O>(op: operator.Scan<I, O>) => (ne: NonEmpty<I>) => List<O>} */
|
|
222
|
+
const scanStep = op => ne => {
|
|
223
|
+
const [o, newOp] = op(ne.first)
|
|
224
|
+
return nonEmpty(o)(scan(newOp)(ne.tail))
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/** @type {<I, O>(op: operator.Scan<I, O>) => (input: List<I>) => List<O>} */
|
|
228
|
+
const scan = op => apply(scanStep(op))
|
|
229
|
+
|
|
230
|
+
/** @type {<I, S, O>(op: operator.StateScan<I, S, O>) => (init: S) => (input: List<I>) => List<O>} */
|
|
231
|
+
const stateScan = op => init => scan(stateScanToScan(op)(init))
|
|
232
|
+
|
|
233
|
+
/** @type {<I,O>(op: operator.Reduce<I, O>) => (init: O) => (input: List<I>) => List<O>} */
|
|
234
|
+
const reduceScan = op => init => scan(reduceToScan(op)(init))
|
|
235
|
+
|
|
236
|
+
/** @type {<I,O>(op: operator.Reduce<I, O>) => (init: O) => (input: List<I>) => O} */
|
|
237
|
+
const reduce = op => init => input => last(init)(reduceScan(op)(init)(input))
|
|
238
|
+
|
|
239
|
+
/** @type {<T>(op: operator.Fold<T>) => <D>(def: D) => (input: List<T>) => D|T} */
|
|
240
|
+
const fold = op => def => input => last(def)(scan(foldToScan(op))(input))
|
|
241
|
+
|
|
242
|
+
const sum = fold(operator.addition)(0)
|
|
243
|
+
|
|
244
|
+
const min = fold(operator.min)(undefined)
|
|
245
|
+
|
|
246
|
+
const max = fold(operator.max)(undefined)
|
|
247
|
+
|
|
248
|
+
/** @type {(separator: string) => (input: List<string>) => string} */
|
|
249
|
+
const join = separator => fold(operator.join(separator))('')
|
|
250
|
+
|
|
251
|
+
/** @type {<T>(input: List<T>) => number} */
|
|
252
|
+
const length = reduce(operator.counter)(0)
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* @template T
|
|
256
|
+
* @typedef {readonly[number, T]} Entry
|
|
257
|
+
*/
|
|
258
|
+
|
|
259
|
+
/** @type {(index: number) => <T>(value: T) => readonly[Entry<T>, number]} */
|
|
260
|
+
const entryOperator = index => value => [[index, value], index + 1]
|
|
261
|
+
|
|
262
|
+
/** @type {<T>(input: List<T>) => List<Entry<T>>} */
|
|
263
|
+
const entries = (input) => {
|
|
264
|
+
/** @typedef {typeof input extends List<infer T> ? T : never} T */
|
|
265
|
+
return stateScan(/** @type {operator.StateScan<T, Number, Entry<T>>} */(entryOperator))(0)(input)
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/** @type {<T>(prior: List<T>) => (value: T) => List<T>} */
|
|
269
|
+
const reverseOperator = prior => value => nonEmpty(value)(prior)
|
|
270
|
+
|
|
271
|
+
/** @type {<T>(input: List<T>) => List<T>} */
|
|
272
|
+
const reverse = reduce(reverseOperator)(undefined)
|
|
273
|
+
|
|
274
|
+
/** @type {<A>(a: A) => <B>(b: B) => readonly[A, B]} */
|
|
275
|
+
const tuple2 = a => b => [a, b]
|
|
276
|
+
|
|
277
|
+
/** @type {<A>(a: List<A>) => <B>(b: List<B>) => List<readonly[A, B]>} */
|
|
278
|
+
const zip = a => b => () => {
|
|
279
|
+
const aResult = next(a)
|
|
280
|
+
if (aResult === undefined) { return undefined }
|
|
281
|
+
const bResult = next(b)
|
|
282
|
+
if (bResult === undefined) { return undefined }
|
|
283
|
+
return nonEmpty(tuple2(aResult.first)(bResult.first))(zip(aResult.tail)(bResult.tail))
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/** @type {<T>(e: operator.Equal<T>) => (a: List<T>) => (b: List<T>) => List<boolean>} */
|
|
287
|
+
const equalZip = e => a => b => () => {
|
|
288
|
+
const [aResult, bResult] = [next(a), next(b)]
|
|
289
|
+
return aResult === undefined || bResult === undefined
|
|
290
|
+
? nonEmpty(aResult === bResult)(undefined)
|
|
291
|
+
: nonEmpty(e(aResult.first)(bResult.first))(equalZip(e)(aResult.tail)(bResult.tail))
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/** @type {<T>(e: operator.Equal<T>) => (a: List<T>) => (b: List<T>) => boolean} */
|
|
295
|
+
const equal = e => a => b => every(equalZip(e)(a)(b))
|
|
296
|
+
|
|
297
|
+
module.exports = {
|
|
298
|
+
/** @readonly */
|
|
299
|
+
empty: undefined,
|
|
300
|
+
/** @readonly */
|
|
301
|
+
nonEmpty,
|
|
302
|
+
/** @readonly */
|
|
303
|
+
concat,
|
|
304
|
+
/** @readonly */
|
|
305
|
+
next,
|
|
306
|
+
/** @readonly */
|
|
307
|
+
iterable,
|
|
308
|
+
/** @readonly */
|
|
309
|
+
toArray,
|
|
310
|
+
/** @readonly */
|
|
311
|
+
flat,
|
|
312
|
+
/** @readonly */
|
|
313
|
+
map,
|
|
314
|
+
/** @readonly */
|
|
315
|
+
flatMap,
|
|
316
|
+
/** @readonly */
|
|
317
|
+
filter,
|
|
318
|
+
/** @readonly */
|
|
319
|
+
filterMap,
|
|
320
|
+
/** @readonly */
|
|
321
|
+
takeWhile,
|
|
322
|
+
/** @readonly */
|
|
323
|
+
take,
|
|
324
|
+
/** @readonly */
|
|
325
|
+
dropWhile,
|
|
326
|
+
/** @readonly */
|
|
327
|
+
drop,
|
|
328
|
+
/** @readonly */
|
|
329
|
+
first,
|
|
330
|
+
/** @readonly */
|
|
331
|
+
last,
|
|
332
|
+
/** @readonly */
|
|
333
|
+
find,
|
|
334
|
+
/** @readonly */
|
|
335
|
+
some,
|
|
336
|
+
/** @readonly */
|
|
337
|
+
every,
|
|
338
|
+
/** @readonly */
|
|
339
|
+
includes,
|
|
340
|
+
/** @readonly */
|
|
341
|
+
countdown,
|
|
342
|
+
/** @readonly */
|
|
343
|
+
cycle,
|
|
344
|
+
/** @readonly */
|
|
345
|
+
scan,
|
|
346
|
+
/** @readonly */
|
|
347
|
+
stateScan,
|
|
348
|
+
/** @readonly */
|
|
349
|
+
reduceScan,
|
|
350
|
+
/** @readonly */
|
|
351
|
+
reduce,
|
|
352
|
+
/** @readonly */
|
|
353
|
+
fold,
|
|
354
|
+
/** @readonly */
|
|
355
|
+
sum,
|
|
356
|
+
/** @readonly */
|
|
357
|
+
min,
|
|
358
|
+
/** @readonly */
|
|
359
|
+
max,
|
|
360
|
+
/** @readonly */
|
|
361
|
+
join,
|
|
362
|
+
/** @readonly */
|
|
363
|
+
length,
|
|
364
|
+
/** @readonly */
|
|
365
|
+
entries,
|
|
366
|
+
/** @readonly */
|
|
367
|
+
reverse,
|
|
368
|
+
/** @readonly */
|
|
369
|
+
zip,
|
|
370
|
+
/** @readonly */
|
|
371
|
+
equal,
|
|
372
|
+
}
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
const _ = require('.')
|
|
2
2
|
const json = require('../../json')
|
|
3
3
|
const { sort } = require('../object')
|
|
4
|
-
const { addition, strictEqual } = require('../function/operator')
|
|
4
|
+
const { addition, strictEqual, foldToScan } = require('../function/operator')
|
|
5
5
|
|
|
6
|
-
/** @type {(sequence: _.
|
|
6
|
+
/** @type {(sequence: _.List<json.Unknown>) => string} */
|
|
7
7
|
const stringify = sequence => json.stringify(sort)(_.toArray(sequence))
|
|
8
8
|
|
|
9
|
+
{
|
|
10
|
+
const x = stringify(_.toArray(_.take(10)(_.cycle([1, 2, 3]))))
|
|
11
|
+
if (x !== '[1,2,3,1,2,3,1,2,3,1]') { throw x }
|
|
12
|
+
}
|
|
13
|
+
|
|
9
14
|
{
|
|
10
15
|
const s = stringify([1, 2, 3])
|
|
11
16
|
if (s !== '[1,2,3]') { throw s }
|
|
@@ -84,7 +89,7 @@ const stringify = sequence => json.stringify(sort)(_.toArray(sequence))
|
|
|
84
89
|
}
|
|
85
90
|
|
|
86
91
|
{
|
|
87
|
-
const op =
|
|
92
|
+
const op = foldToScan(addition)
|
|
88
93
|
const result = stringify(_.scan(op)([2, 3, 4, 5]))
|
|
89
94
|
if (result !== '[2,5,9,14]') { throw result }
|
|
90
95
|
}
|
|
@@ -130,7 +135,7 @@ const stringify = sequence => json.stringify(sort)(_.toArray(sequence))
|
|
|
130
135
|
}
|
|
131
136
|
|
|
132
137
|
{
|
|
133
|
-
const result = stringify(_.reverse([1,2,3,4,5]))
|
|
138
|
+
const result = stringify(_.reverse([1, 2, 3, 4, 5]))
|
|
134
139
|
if (result !== '[5,4,3,2,1]') { throw result }
|
|
135
140
|
}
|
|
136
141
|
|
|
@@ -146,7 +151,7 @@ const stringify = sequence => json.stringify(sort)(_.toArray(sequence))
|
|
|
146
151
|
|
|
147
152
|
{
|
|
148
153
|
const result = _.some(_.map(x => x > 5)([0, 1, 7]))
|
|
149
|
-
if (!result) { throw result}
|
|
154
|
+
if (!result) { throw result }
|
|
150
155
|
}
|
|
151
156
|
|
|
152
157
|
{
|
|
@@ -176,7 +181,7 @@ const stringify = sequence => json.stringify(sort)(_.toArray(sequence))
|
|
|
176
181
|
|
|
177
182
|
{
|
|
178
183
|
const result = _.equal(strictEqual)([1])([2, 3])
|
|
179
|
-
if (result) { throw result}
|
|
184
|
+
if (result) { throw result }
|
|
180
185
|
}
|
|
181
186
|
|
|
182
187
|
{
|
|
@@ -214,8 +219,8 @@ const stringify = sequence => json.stringify(sort)(_.toArray(sequence))
|
|
|
214
219
|
const stress = () => {
|
|
215
220
|
|
|
216
221
|
{
|
|
217
|
-
//
|
|
218
|
-
const n =
|
|
222
|
+
// 200_000_000 is too much
|
|
223
|
+
const n = 100_000_000
|
|
219
224
|
const result = _.toArray(_.countdown(n))
|
|
220
225
|
if (result.length !== n) { throw result.length }
|
|
221
226
|
const len = _.length(_.filter(x => x > n)(result))
|
|
@@ -225,26 +230,30 @@ const stress = () => {
|
|
|
225
230
|
console.log('first')
|
|
226
231
|
|
|
227
232
|
{
|
|
228
|
-
//
|
|
229
|
-
const n =
|
|
233
|
+
// 100_000_000 is too much
|
|
234
|
+
const n = 50_000_000
|
|
230
235
|
const result = _.toArray(_.countdown(n))
|
|
231
236
|
if (result.length !== n) { throw result.length }
|
|
232
237
|
const first = _.first(undefined)(result)
|
|
233
238
|
if (first !== n - 1) { throw first }
|
|
234
239
|
}
|
|
235
240
|
|
|
241
|
+
console.log('concat back')
|
|
242
|
+
|
|
236
243
|
{
|
|
237
|
-
/** @type {_.
|
|
244
|
+
/** @type {_.List<number>} */
|
|
238
245
|
let sequence = []
|
|
239
|
-
//
|
|
240
|
-
for (let i = 0; i <
|
|
246
|
+
// 20_000_000 is too much
|
|
247
|
+
for (let i = 0; i < 10_000_000; ++i) {
|
|
241
248
|
sequence = _.concat(sequence)([i])
|
|
242
249
|
}
|
|
243
250
|
const r = _.toArray(sequence)
|
|
244
251
|
}
|
|
245
252
|
|
|
253
|
+
console.log('flat to Array')
|
|
254
|
+
|
|
246
255
|
{
|
|
247
|
-
/** @type {_.
|
|
256
|
+
/** @type {_.List<number>} */
|
|
248
257
|
let sequence = []
|
|
249
258
|
// 4_000_000 is too much
|
|
250
259
|
for (let i = 0; i < 2_000_000; ++i) {
|
|
@@ -253,18 +262,22 @@ const stress = () => {
|
|
|
253
262
|
const r = _.toArray(sequence)
|
|
254
263
|
}
|
|
255
264
|
|
|
265
|
+
console.log('flat next')
|
|
266
|
+
|
|
256
267
|
{
|
|
257
|
-
/** @type {_.
|
|
268
|
+
/** @type {_.List<number>} */
|
|
258
269
|
let sequence = []
|
|
259
270
|
// 5_000_000 is too much
|
|
260
|
-
for (let i = 0; i <
|
|
271
|
+
for (let i = 0; i < 4_000_000; ++i) {
|
|
261
272
|
sequence = _.flat([sequence, [i]])
|
|
262
273
|
}
|
|
263
274
|
const a = _.next(sequence)
|
|
264
275
|
}
|
|
265
276
|
|
|
277
|
+
console.log('concat front')
|
|
278
|
+
|
|
266
279
|
{
|
|
267
|
-
/** @type {_.
|
|
280
|
+
/** @type {_.List<number>} */
|
|
268
281
|
let sequence = []
|
|
269
282
|
// 20_000_000 is too much
|
|
270
283
|
for (let i = 0; i < 10_000_000; ++i) {
|
|
@@ -274,7 +287,7 @@ const stress = () => {
|
|
|
274
287
|
}
|
|
275
288
|
|
|
276
289
|
{
|
|
277
|
-
/** @type {_.
|
|
290
|
+
/** @type {_.List<number>} */
|
|
278
291
|
let sequence = []
|
|
279
292
|
// 10_000_000 is too much
|
|
280
293
|
for (let i = 0; i < 5_000_000; ++i) {
|
|
@@ -306,7 +319,7 @@ const stress = () => {
|
|
|
306
319
|
}
|
|
307
320
|
}
|
|
308
321
|
|
|
309
|
-
|
|
322
|
+
stress()
|
|
310
323
|
|
|
311
324
|
module.exports = {
|
|
312
325
|
|
package/types/map/index.js
CHANGED
|
@@ -3,7 +3,7 @@ const btree = require('../btree')
|
|
|
3
3
|
const { getVisitor, setVisitor, values } = require("../btree")
|
|
4
4
|
const compare = require("../function/compare")
|
|
5
5
|
const { cmp } = require("../function/compare")
|
|
6
|
-
const seq = require("../
|
|
6
|
+
const seq = require("../list")
|
|
7
7
|
|
|
8
8
|
/** @typedef {compare.Sign} Sign */
|
|
9
9
|
|
|
@@ -54,15 +54,15 @@ const set = name => value => map => {
|
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
/** @type {<T>(map: Map<T>) => seq.
|
|
57
|
+
/** @type {<T>(map: Map<T>) => seq.List<Entry<T>>} */
|
|
58
58
|
const entries = map => map === undefined ? [] : values(map)
|
|
59
59
|
|
|
60
60
|
/** @type {<T>(map: Map<T>) => (entry: Entry<T>) => Map<T>} */
|
|
61
61
|
const setOp = map => ([name, value]) => set(name)(value)(map)
|
|
62
62
|
|
|
63
|
-
/** @type {<T>(entries: seq.
|
|
63
|
+
/** @type {<T>(entries: seq.List<Entry<T>>) => Map<T>} */
|
|
64
64
|
const fromEntries = entries => {
|
|
65
|
-
/** @typedef {typeof entries extends seq.
|
|
65
|
+
/** @typedef {typeof entries extends seq.List<Entry<infer T>> ? T : never} T */
|
|
66
66
|
return seq.reduce(setOp)(/** @type {Map<T>} */(undefined))(entries)
|
|
67
67
|
}
|
|
68
68
|
|
package/types/map/test.js
CHANGED
package/types/object/index.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
const seq = require('../
|
|
1
|
+
const seq = require('../list')
|
|
2
2
|
const map = require('../map')
|
|
3
|
-
const { compose } = require('../function')
|
|
4
3
|
|
|
5
4
|
/**
|
|
6
5
|
* @template T
|
|
@@ -17,7 +16,7 @@ const { compose } = require('../function')
|
|
|
17
16
|
/** @type {(name: string) => <T>(object: Map<T>) => T|undefined} */
|
|
18
17
|
const at = name => object => Object.getOwnPropertyDescriptor(object, name)?.value
|
|
19
18
|
|
|
20
|
-
/** @type {<T>(entries: seq.
|
|
19
|
+
/** @type {<T>(entries: seq.List<Entry<T>>) => seq.List<Entry<T>>} */
|
|
21
20
|
const sort = entries => map.entries(map.fromEntries(entries))
|
|
22
21
|
|
|
23
22
|
module.exports = {
|
package/types/sequence/README.md
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
# Sequences
|
|
2
|
-
|
|
3
|
-
Sequence types:
|
|
4
|
-
|
|
5
|
-
- Sequence
|
|
6
|
-
- Array
|
|
7
|
-
- Iterable
|
|
8
|
-
- AsyncIterable
|
|
9
|
-
|
|
10
|
-
# Sequence Types
|
|
11
|
-
|
|
12
|
-
```ts
|
|
13
|
-
type Sequence<T> =
|
|
14
|
-
readonly T[] |
|
|
15
|
-
Thunk<T> |
|
|
16
|
-
|
|
17
|
-
type Thunk<T> = () => Node<T>
|
|
18
|
-
|
|
19
|
-
type Node<T> =
|
|
20
|
-
undefined |
|
|
21
|
-
{ readonly first: T, readonly tail: Sequence<T> } |
|
|
22
|
-
readonly[Sequence<T>, Sequence<T>]
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
## Functions
|
|
26
|
-
|
|
27
|
-
See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array
|
|
28
|
-
|
|
29
|
-
- `length: Sequence<infer T> => number`
|
|
30
|
-
- `at: number => Sequence<infer T> = T|undefined`
|
|
31
|
-
- `concat: Sequence<infer T> => Sequence<T> => Sequence<T>`
|
|
32
|
-
- `entries: Sequence<infer T> => Sequence<[number, T]>`
|
|
33
|
-
- `every: (infer T => boolean) => Sequence<T> => boolean`
|
|
34
|
-
- `filter: (infer T => boolean) => Sequence<T> => Sequence<T>`
|
|
35
|
-
- `find: (infer T => boolean) => Sequence<T> => T`
|
|
36
|
-
- `findIndex: (infer T => boolean) => Sequence<T> => number`
|
|
37
|
-
- `flat: Sequence<Sequence<T>> => Sequence<T>`
|
|
38
|
-
- `flatMap: (infer T => Sequence<infer R>) => Sequence<T> => Sequence<R>`
|
|
39
|
-
- `includes: infer T => Sequence<T> => boolean`
|
|
40
|
-
- `indexOf: infer T => Sequence<T> => number`
|
|
41
|
-
- `join: string => Sequence<string> => string`
|
|
42
|
-
- `lastIndexOf: infer T => Sequence<T> => number`
|
|
43
|
-
- `map: (infer T => infer R) => Sequence<T> => Sequence<R>`
|
|
44
|
-
- `reduce: ...Scan<T, R> => Sequence<T> => R`
|
|
45
|
-
- `some: (infer T => boolean) => Sequence<T> => boolean`
|
|
46
|
-
|
|
47
|
-
### Priority 2.
|
|
48
|
-
|
|
49
|
-
- `slice: number => number => Sequence<T> => Sequence<T>`
|
|
50
|
-
- `reduceRight: ...Scan<T, R> => Sequence<T> => R`
|
|
51
|
-
- `toLocalString: Locales => Sequence<T> => string`
|
|
52
|
-
|
|
53
|
-
### Priority 3.
|
|
54
|
-
|
|
55
|
-
- `keys: Sequence<T> => Sequence<string>`
|
|
56
|
-
- `values: Sequence<infer T> => Sequence<T>`
|
|
57
|
-
|
|
58
|
-
## Prohibited Array Operations
|
|
59
|
-
|
|
60
|
-
- `copyWithin`
|
|
61
|
-
- `fill`
|
|
62
|
-
- `pop`
|
|
63
|
-
- `push`
|
|
64
|
-
- `reverse`
|
|
65
|
-
- `shift`
|
|
66
|
-
- `sort`
|
|
67
|
-
- `splice`
|
|
68
|
-
- `unshift`
|
package/types/sequence/index.js
DELETED
|
@@ -1,382 +0,0 @@
|
|
|
1
|
-
const { compose, identity } = require('../function')
|
|
2
|
-
const { logicalNot, strictEqual, addition } = require('../function/operator')
|
|
3
|
-
const op = require('../function/operator')
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* @template T
|
|
7
|
-
* @typedef { readonly T[] | Thunk<T> } Sequence<T>
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* @template T
|
|
12
|
-
* @typedef { () => Node<T> } Thunk
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* @template T
|
|
17
|
-
* @typedef { Result<T> | Concat<T> } Node<T>
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* @template T
|
|
22
|
-
* @typedef { readonly[Sequence<T>, Sequence<T>] } Concat<T>
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* @template T
|
|
27
|
-
* @typedef { undefined | ResultOne<T> } Result
|
|
28
|
-
*/
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* @template T
|
|
32
|
-
* @typedef {{ readonly first: T, readonly tail: Sequence<T> }} ResultOne
|
|
33
|
-
*/
|
|
34
|
-
|
|
35
|
-
const empty = () => undefined
|
|
36
|
-
|
|
37
|
-
/** @type {<T>(first: T) => (tail: Sequence<T>) => Sequence<T>} */
|
|
38
|
-
const sequence = first => tail => () => ({ first, tail })
|
|
39
|
-
|
|
40
|
-
/** @type {<T>(sequence: Sequence<T>) => Node<T>} */
|
|
41
|
-
const nodeOne = sequence => [empty, sequence]
|
|
42
|
-
|
|
43
|
-
/** @type {<T>(array: readonly T[]) => Result<T>} */
|
|
44
|
-
const fromArray = array => {
|
|
45
|
-
/** @typedef {typeof array extends readonly(infer T)[] ? T : never} T */
|
|
46
|
-
/** @type {(index: number) => Result<T>} */
|
|
47
|
-
const at = index => {
|
|
48
|
-
if (array.length <= index) { return undefined }
|
|
49
|
-
return { first: array[index], tail: () => at(index + 1) }
|
|
50
|
-
}
|
|
51
|
-
return at(0)
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/** @type {<T>(sequence: Sequence<T>) => Node<T>} */
|
|
55
|
-
const node = sequence => sequence instanceof Array ? fromArray(sequence) : sequence()
|
|
56
|
-
|
|
57
|
-
/** @type {<T>(a: Sequence<T>) => (b: Sequence<T>) => Thunk<T>} */
|
|
58
|
-
const concat = a => b => () => [a, b]
|
|
59
|
-
|
|
60
|
-
/** @type {<T>(sequence: Sequence<T>) => Result<T>} */
|
|
61
|
-
const next = sequence => {
|
|
62
|
-
let i = sequence
|
|
63
|
-
while (true) {
|
|
64
|
-
const n = node(i)
|
|
65
|
-
if (!(n instanceof Array)) { return n }
|
|
66
|
-
const [a, b] = n
|
|
67
|
-
const aNode = node(a)
|
|
68
|
-
if (aNode === undefined) {
|
|
69
|
-
i = b
|
|
70
|
-
} else if (aNode instanceof Array) {
|
|
71
|
-
const [aa, ab] = aNode
|
|
72
|
-
i = concat(aa)(concat(ab)(b))
|
|
73
|
-
} else {
|
|
74
|
-
const { first, tail } = aNode
|
|
75
|
-
return { first, tail: concat(tail)(b) }
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/** @type {<T>(sequence: Sequence<T>) => Iterable<T>} */
|
|
81
|
-
const iterable = sequence => ({
|
|
82
|
-
*[Symbol.iterator]() {
|
|
83
|
-
let i = sequence
|
|
84
|
-
while (true) {
|
|
85
|
-
const n = next(i)
|
|
86
|
-
if (n === undefined) { return }
|
|
87
|
-
const { first, tail } = n
|
|
88
|
-
yield first
|
|
89
|
-
i = tail
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
})
|
|
93
|
-
|
|
94
|
-
/** @type {<T>(sequence: Sequence<T>) => readonly T[]} */
|
|
95
|
-
const toArray = sequence => {
|
|
96
|
-
if (sequence instanceof Array) { return sequence }
|
|
97
|
-
return Array.from(iterable(sequence))
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/** @type {<I, O>(step: (result: ResultOne<I>) => Node<O>) => (input: Sequence<I>) => Thunk<O>} */
|
|
101
|
-
const apply = f => input => () => {
|
|
102
|
-
const n = next(input)
|
|
103
|
-
if (n === undefined) { return undefined }
|
|
104
|
-
return f(n)
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/** @type {<T>(result: ResultOne<Sequence<T>>) => Node<T>} */
|
|
108
|
-
const flatStep = ({first, tail}) => [first, flat(tail)]
|
|
109
|
-
|
|
110
|
-
/** @type {<T>(sequence: Sequence<Sequence<T>>) => Thunk<T>} */
|
|
111
|
-
const flat = apply(flatStep)
|
|
112
|
-
|
|
113
|
-
/** @type {<I, O>(f: (value: I) => O) => (result: ResultOne<I>) => Node<O>} */
|
|
114
|
-
const mapStep = f => ({ first, tail }) => ({ first: f(first), tail: map(f)(tail) })
|
|
115
|
-
|
|
116
|
-
/** @type {<I, O>(f: (value: I) => O) => (input: Sequence<I>) => Thunk<O>} */
|
|
117
|
-
const map = f => apply(mapStep(f))
|
|
118
|
-
|
|
119
|
-
/** @type {<I, O>(f: (value: I) => Sequence<O>) => (input: Sequence<I>) => Thunk<O>} */
|
|
120
|
-
const flatMap = f => compose(map(f))(flat)
|
|
121
|
-
|
|
122
|
-
/** @type {<T>(f: (value: T) => boolean) => (result: ResultOne<T>) => Node<T>} */
|
|
123
|
-
const filterStep = f => ({ first, tail }) => {
|
|
124
|
-
const fTail = filter(f)(tail)
|
|
125
|
-
return f(first) ? { first, tail: fTail } : nodeOne(fTail)
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/** @type {<T>(f: (value: T) => boolean) => (input: Sequence<T>) => Thunk<T>} */
|
|
129
|
-
const filter = f => apply(filterStep(f))
|
|
130
|
-
|
|
131
|
-
/** @type {<I, O>(f: (value: I) => O|undefined) => (result: ResultOne<I>) => Node<O>} */
|
|
132
|
-
const filterMapStep = f => ({first, tail}) => {
|
|
133
|
-
const fFirst = f(first)
|
|
134
|
-
const fTail = filterMap(f)(tail)
|
|
135
|
-
return fFirst === undefined ? nodeOne(fTail) : { first: fFirst, tail: fTail }
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/** @type {<I, O>(f: (value: I) => O|undefined) => (input: Sequence<I>) => Thunk<O>} */
|
|
139
|
-
const filterMap = f => apply(filterMapStep(f))
|
|
140
|
-
|
|
141
|
-
/** @type {<T>(f: (value: T) => boolean) => (result: ResultOne<T>) => Node<T>} */
|
|
142
|
-
const takeWhileStep = f => ({ first, tail }) => f(first) ? { first, tail: takeWhile(f)(tail) } :undefined
|
|
143
|
-
|
|
144
|
-
/** @type {<T>(f: (value: T) => boolean) => (input: Sequence<T>) => Thunk<T>} */
|
|
145
|
-
const takeWhile = f => apply(takeWhileStep(f))
|
|
146
|
-
|
|
147
|
-
/** @type {(n: number) => <T>(result: ResultOne<T>) => Node<T>} */
|
|
148
|
-
const takeStep = n => ({ first, tail }) => 0 < n ? { first, tail: take(n - 1)(tail) } : undefined
|
|
149
|
-
|
|
150
|
-
/** @type {(n: number) => <T>(result: Sequence<T>) => Sequence<T>} */
|
|
151
|
-
const take = n => apply(takeStep(n))
|
|
152
|
-
|
|
153
|
-
/** @type {<T>(f: (value: T) => boolean) => (result: ResultOne<T>) => Node<T>} */
|
|
154
|
-
const dropWhileStep = f => result => {
|
|
155
|
-
const { first, tail } = result
|
|
156
|
-
return f(first) ? nodeOne(dropWhile(f)(tail)) : result
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/** @type {<T>(f: (value: T) => boolean) => (input: Sequence<T>) => Thunk<T>} */
|
|
160
|
-
const dropWhile = f => apply(dropWhileStep(f))
|
|
161
|
-
|
|
162
|
-
/** @type {(n: number) => <T>(result: ResultOne<T>) => Node<T>} */
|
|
163
|
-
const dropFn = n => result => 0 < n ? nodeOne(drop(n - 1)(result.tail)) : result
|
|
164
|
-
|
|
165
|
-
/** @type {(n: number) => <T>(result: Sequence<T>) => Sequence<T>} */
|
|
166
|
-
const drop = n => apply(dropFn(n))
|
|
167
|
-
|
|
168
|
-
/** @type {<D>(def: D) => <T>(input: Sequence<T>) => D|T} */
|
|
169
|
-
const first = def => input => {
|
|
170
|
-
const result = next(input)
|
|
171
|
-
if (result === undefined) { return def }
|
|
172
|
-
return result.first
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/** @type {<D>(def: D) => <T>(input: Sequence<T>) => D|T} */
|
|
176
|
-
const last = def => input => {
|
|
177
|
-
/** @typedef {typeof input extends Sequence<infer T> ? T : never} T */
|
|
178
|
-
/** @type {(typeof def)|T} */
|
|
179
|
-
let r = def
|
|
180
|
-
let i = input
|
|
181
|
-
while (true) {
|
|
182
|
-
const result = next(i)
|
|
183
|
-
if (result === undefined) {
|
|
184
|
-
return r
|
|
185
|
-
}
|
|
186
|
-
r = result.first
|
|
187
|
-
i = result.tail
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/** @type {<D>(def: D) => <T>(f: (value: T) => boolean) => (sequence: Sequence<T>) => D|T} */
|
|
192
|
-
const find = def => f => input => first(def)(filter(f)(input))
|
|
193
|
-
|
|
194
|
-
/** @type {(value: boolean) => boolean} */
|
|
195
|
-
const boolIdentity = identity
|
|
196
|
-
|
|
197
|
-
/** @type {(sequence: Sequence<boolean>) => boolean} */
|
|
198
|
-
const some = input => find(false)(boolIdentity)(input)
|
|
199
|
-
|
|
200
|
-
/** @type {(sequence: Sequence<boolean>) => boolean} */
|
|
201
|
-
const every = input => !some(map(logicalNot)(input))
|
|
202
|
-
|
|
203
|
-
/** @type {<T>(value: T) => (sequence: Sequence<T>) => boolean} */
|
|
204
|
-
const includes = value => input => some(map(strictEqual(value))(input))
|
|
205
|
-
|
|
206
|
-
/** @type {(count: number) => Thunk<number>} */
|
|
207
|
-
const countdown = count => () => {
|
|
208
|
-
if (count <= 0) { return undefined }
|
|
209
|
-
const first = count - 1
|
|
210
|
-
return { first, tail: countdown(first) }
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* @template T,A
|
|
215
|
-
* @typedef {(value: T) => ScanState<T, A>} ScanOperator
|
|
216
|
-
*/
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* @template T,A
|
|
220
|
-
* @typedef {readonly[A, ScanOperator<T, A>]} ScanState
|
|
221
|
-
*/
|
|
222
|
-
|
|
223
|
-
/** @type {<T,A>(operator: ScanOperator<T, A>) => (result: ResultOne<T>) => Node<A>} */
|
|
224
|
-
const scanFn = operator => ({first, tail}) => {
|
|
225
|
-
const [value, nextOperator] = operator(first)
|
|
226
|
-
return { first: value, tail: scan(nextOperator)(tail) }
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
/** @type {<T,A>(operator: ScanOperator<T, A>) => (input: Sequence<T>) => Thunk<A>} */
|
|
230
|
-
const scan = operator => apply(scanFn(operator))
|
|
231
|
-
|
|
232
|
-
/** @type {<T,A>(operator: ScanOperator<T, A>) => <D>(def: D)=> (input: Sequence<T>) => D|A} */
|
|
233
|
-
const scanReduce = operator => def => input => last(def)(scan(operator)(input))
|
|
234
|
-
|
|
235
|
-
/**
|
|
236
|
-
* @template T,A
|
|
237
|
-
* @typedef {(prior: A) => (value: T) => A} ReduceOperator
|
|
238
|
-
*/
|
|
239
|
-
|
|
240
|
-
/** @type {<T,A>(operator: ReduceOperator<T, A>) => (init: A) => ScanState<T, A>} */
|
|
241
|
-
const scanState = operator => init => [init, scanOperator(operator)(init)]
|
|
242
|
-
|
|
243
|
-
/** @type {<T,A>(operator: ReduceOperator<T, A>) => (init: A) => ScanOperator<T, A>} */
|
|
244
|
-
const scanOperator = operator => init => value => scanState(operator)(operator(init)(value))
|
|
245
|
-
|
|
246
|
-
/** @type {<T,A>(operator: ReduceOperator<T, A>) => (init: A) => (input: Sequence<T>) => A} */
|
|
247
|
-
const reduce = operator => init => scanReduce(scanOperator(operator)(init))(init)
|
|
248
|
-
|
|
249
|
-
/**
|
|
250
|
-
* @template T
|
|
251
|
-
* @typedef {ReduceOperator<T, T>} FoldOperator
|
|
252
|
-
*/
|
|
253
|
-
|
|
254
|
-
/** @type {<T>(operator: FoldOperator<T>) => <D>(def: D) => (input: Sequence<T>) => D|T} */
|
|
255
|
-
const fold = operator => def => scanReduce(scanState(operator))(def)
|
|
256
|
-
|
|
257
|
-
const sum = fold(addition)(0)
|
|
258
|
-
|
|
259
|
-
const min = fold(op.min)(undefined)
|
|
260
|
-
|
|
261
|
-
const max = fold(op.max)(undefined)
|
|
262
|
-
|
|
263
|
-
/** @type {(separator: string) => (input: Sequence<string>) => string} */
|
|
264
|
-
const join = separator => fold(op.join(separator))('')
|
|
265
|
-
|
|
266
|
-
/** @type {(a: number) => () => number} */
|
|
267
|
-
const counter = a => () => a + 1
|
|
268
|
-
|
|
269
|
-
/** @type {<T>(input: Sequence<T>) => number} */
|
|
270
|
-
const length = reduce(counter)(0)
|
|
271
|
-
|
|
272
|
-
/**
|
|
273
|
-
* @template T
|
|
274
|
-
* @typedef {readonly[number, T]} Entry
|
|
275
|
-
*/
|
|
276
|
-
|
|
277
|
-
/** @type {(index: number) => <T>(value: T) => ScanState<T, Entry<T>>} */
|
|
278
|
-
const entryOp = index => value => [[index, value], entryOp(index + 1)]
|
|
279
|
-
|
|
280
|
-
/** @type {<T>(input: Sequence<T>) => Thunk<Entry<T>>} */
|
|
281
|
-
const entries = scan(entryOp(0))
|
|
282
|
-
|
|
283
|
-
/** @type {<T>(prior: Sequence<T>) => (value: T) => Sequence<T>} */
|
|
284
|
-
const reverseOp = prior => value => sequence(value)(prior)
|
|
285
|
-
|
|
286
|
-
/** @type {<T>(input: Sequence<T>) => Sequence<T>} */
|
|
287
|
-
const reverse = reduce(reverseOp)(empty)
|
|
288
|
-
|
|
289
|
-
/** @type {<A>(a: Sequence<A>) => <B>(b: Sequence<B>) => Thunk<readonly[A, B]>} */
|
|
290
|
-
const zip = a => b => () => {
|
|
291
|
-
const aResult = next(a)
|
|
292
|
-
if (aResult === undefined) { return undefined }
|
|
293
|
-
const bResult = next(b)
|
|
294
|
-
if (bResult === undefined) { return undefined }
|
|
295
|
-
return { first: [aResult.first, bResult.first], tail: zip(aResult.tail)(bResult.tail) }
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
/** @type {<T>(e: op.EqualOperator<T>) => (a: Sequence<T>) => (b: Sequence<T>) => Thunk<boolean>} */
|
|
299
|
-
const equalZip = e => a => b => () => {
|
|
300
|
-
const aResult = next(a)
|
|
301
|
-
const bResult = next(b)
|
|
302
|
-
if (aResult === undefined || bResult === undefined) {
|
|
303
|
-
return { first: aResult === bResult, tail: empty }
|
|
304
|
-
}
|
|
305
|
-
return { first: e(aResult.first)(bResult.first), tail: equalZip(e)(aResult.tail)(bResult.tail) }
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
/** @type {<T>(e: op.EqualOperator<T>) => (a: Sequence<T>) => (b: Sequence<T>) => boolean} */
|
|
309
|
-
const equal = e => a => b => every(equalZip(e)(a)(b))
|
|
310
|
-
|
|
311
|
-
module.exports = {
|
|
312
|
-
/** @readonly */
|
|
313
|
-
sequence,
|
|
314
|
-
/** @readonly */
|
|
315
|
-
iterable,
|
|
316
|
-
/** @readonly */
|
|
317
|
-
next,
|
|
318
|
-
/** @readonly */
|
|
319
|
-
toArray,
|
|
320
|
-
/** @readonly */
|
|
321
|
-
flat,
|
|
322
|
-
/** @readonly */
|
|
323
|
-
last,
|
|
324
|
-
/** @readonly */
|
|
325
|
-
concat,
|
|
326
|
-
/** @readonly */
|
|
327
|
-
first,
|
|
328
|
-
/** @readonly */
|
|
329
|
-
map,
|
|
330
|
-
/** @readonly */
|
|
331
|
-
flatMap,
|
|
332
|
-
/** @readonly */
|
|
333
|
-
filter,
|
|
334
|
-
/** @readonly */
|
|
335
|
-
filterMap,
|
|
336
|
-
/** @readonly */
|
|
337
|
-
find,
|
|
338
|
-
/** @readonly */
|
|
339
|
-
some,
|
|
340
|
-
/** @readonly */
|
|
341
|
-
every,
|
|
342
|
-
/** @readonly */
|
|
343
|
-
includes,
|
|
344
|
-
/** @readonly */
|
|
345
|
-
takeWhile,
|
|
346
|
-
/** @readonly */
|
|
347
|
-
take,
|
|
348
|
-
/** @readonly */
|
|
349
|
-
dropWhile,
|
|
350
|
-
/** @readonly */
|
|
351
|
-
drop,
|
|
352
|
-
/** @readonly */
|
|
353
|
-
scanOperator,
|
|
354
|
-
/** @readonly */
|
|
355
|
-
scanState,
|
|
356
|
-
/** @readonly */
|
|
357
|
-
scan,
|
|
358
|
-
/** @readonly */
|
|
359
|
-
reduce,
|
|
360
|
-
/** @readonly */
|
|
361
|
-
fold,
|
|
362
|
-
/** @readonly */
|
|
363
|
-
sum,
|
|
364
|
-
/** @readonly */
|
|
365
|
-
min,
|
|
366
|
-
/** @readonly */
|
|
367
|
-
max,
|
|
368
|
-
/** @readonly */
|
|
369
|
-
join,
|
|
370
|
-
/** @readonly */
|
|
371
|
-
entries,
|
|
372
|
-
/** @readonly */
|
|
373
|
-
length,
|
|
374
|
-
/** @readonly */
|
|
375
|
-
reverse,
|
|
376
|
-
/** @readonly */
|
|
377
|
-
zip,
|
|
378
|
-
/** @readonly */
|
|
379
|
-
equal,
|
|
380
|
-
/** @readonly */
|
|
381
|
-
countdown,
|
|
382
|
-
}
|