functionalscript 0.0.239 → 0.0.243
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/.github/workflows/node.js.yml +0 -2
- package/LICENSE +21 -201
- package/commonjs/README.md +55 -0
- package/commonjs/module/index.js +23 -10
- package/commonjs/package/dependencies/index.js +1 -1
- package/commonjs/package/dependencies/test.js +0 -3
- package/commonjs/package/index.js +7 -2
- package/commonjs/path/index.js +9 -9
- package/io/nodejs/version/index.js +1 -6
- package/json/index.js +16 -16
- package/package.json +9 -2
- package/test.js +1 -1
- package/tsconfig.json +1 -1
- package/types/array/index.js +1 -1
- package/types/btree/index.js +23 -25
- 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 +9 -9
- package/types/map/test.js +11 -11
- package/types/object/index.js +2 -3
- package/types/sequence/README.md +0 -68
- package/types/sequence/index.js +0 -382
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
|
|
@@ -129,41 +129,39 @@ const seq = require('../sequence')
|
|
|
129
129
|
const split = ([n0, v1, n2, v3, n4, v5, n6]) => [[n0, v1, n2], v3, [n4, v5, n6]]
|
|
130
130
|
|
|
131
131
|
/**
|
|
132
|
-
* @type {<T>(
|
|
132
|
+
* @type {<T>(extend: (o: Branch3<T>) => Result<T>) =>
|
|
133
133
|
* (replace: (r: Node<T>) => Node<T>) =>
|
|
134
134
|
* (result: Result<T>) =>
|
|
135
135
|
* Result<T>}
|
|
136
136
|
*/
|
|
137
|
-
const merge =
|
|
137
|
+
const merge = extend => replace => result => {
|
|
138
138
|
switch (result[0]) {
|
|
139
139
|
case 'done': { return result }
|
|
140
140
|
case 'replace': { return ['replace', replace(result[1])] }
|
|
141
|
-
default: { return
|
|
141
|
+
default: { return extend(result[1]) }
|
|
142
142
|
}
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
-
/**
|
|
146
|
-
* @type {<T>(overflow: (o: Branch3<T>) => Branch5<T>) =>
|
|
147
|
-
* (replace: (r: Node<T>) => Branch3<T>) =>
|
|
148
|
-
* (result: Result<T>) =>
|
|
149
|
-
* Result<T>}
|
|
150
|
-
*/
|
|
151
|
-
const merge2 = overflow => merge(o => ['replace', overflow(o)])
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* @type {<T>(overflow: (o: Branch3<T>) => Branch7<T>) =>
|
|
155
|
-
* (replace: (r: Node<T>) => Branch5<T>) =>
|
|
156
|
-
* (result: Result<T>) =>
|
|
157
|
-
* Result<T>}
|
|
158
|
-
*/
|
|
159
|
-
const merge3 = overflow => merge(o => ['overflow', split(overflow(o))])
|
|
160
|
-
|
|
161
145
|
/** @type {(visitor: Visitor) => <T>(cmp: Cmp<T>) => (init: Lazy<T>) => (node: Node<T>) => Result<T>} */
|
|
162
146
|
const visit = ({ found, notFound }) => cmp => {
|
|
163
147
|
const i3 = index3(cmp)
|
|
164
148
|
const i5 = index5(cmp)
|
|
149
|
+
/** @typedef {typeof cmp extends Cmp<infer T> ? T : never} T */
|
|
150
|
+
/**
|
|
151
|
+
* @type {(extend: (o: Branch3<T>) => Branch5<T>) =>
|
|
152
|
+
* (replace: (r: Node<T>) => Branch3<T>) =>
|
|
153
|
+
* (result: Result<T>) =>
|
|
154
|
+
* Result<T>}
|
|
155
|
+
*/
|
|
156
|
+
const merge2 = extend => merge(o => ['replace', extend(o)])
|
|
157
|
+
/**
|
|
158
|
+
* @type {(extend: (o: Branch3<T>) => Branch7<T>) =>
|
|
159
|
+
* (replace: (r: Node<T>) => Branch5<T>) =>
|
|
160
|
+
* (result: Result<T>) =>
|
|
161
|
+
* Result<T>}
|
|
162
|
+
*/
|
|
163
|
+
const merge3 = extend => merge(o => ['overflow', split(extend(o))])
|
|
165
164
|
return init => {
|
|
166
|
-
/** @typedef {typeof cmp extends Cmp<infer T> ? T : never} T*/
|
|
167
165
|
/** @type {(node: Node<T>) => Result<T>} */
|
|
168
166
|
const f = node => {
|
|
169
167
|
switch (node.length) {
|
|
@@ -188,14 +186,14 @@ const visit = ({ found, notFound }) => cmp => {
|
|
|
188
186
|
switch (i3(v1)) {
|
|
189
187
|
case 0: {
|
|
190
188
|
return merge2
|
|
191
|
-
(
|
|
189
|
+
(e => [...e, v1, n2])
|
|
192
190
|
(r => [r, v1, n2])
|
|
193
191
|
(f(n0))
|
|
194
192
|
}
|
|
195
193
|
case 1: { return found.branch3(init)(node) }
|
|
196
194
|
default: {
|
|
197
195
|
return merge2
|
|
198
|
-
(
|
|
196
|
+
(e => [n0, v1, ...e])
|
|
199
197
|
(r => [n0, v1, r])
|
|
200
198
|
(f(n2))
|
|
201
199
|
}
|
|
@@ -305,7 +303,7 @@ const replaceVisitor = {
|
|
|
305
303
|
notFound: notFoundGet,
|
|
306
304
|
}
|
|
307
305
|
|
|
308
|
-
/** @type {<T>(node: Node<T>) => seq.
|
|
306
|
+
/** @type {<T>(node: Node<T>) => seq.List<T>} */
|
|
309
307
|
const values = node => () => {
|
|
310
308
|
const f = () => {
|
|
311
309
|
switch (node.length) {
|
|
@@ -339,7 +337,7 @@ module.exports = {
|
|
|
339
337
|
* @type { <T>(cmp: Cmp<T>) => (node: Node<T>) => T|undefined }
|
|
340
338
|
*/
|
|
341
339
|
getVisitor: cmp => node => {
|
|
342
|
-
const result = visit(getVisitor)(cmp)(() => { throw '' })(node)
|
|
340
|
+
const result = visit(getVisitor)(cmp)(() => { throw 'getVisitor' })(node)
|
|
343
341
|
if (result[0] === 'done') { return result[1] }
|
|
344
342
|
return undefined
|
|
345
343
|
},
|
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
|
+
}
|