functionalscript 0.0.222 → 0.0.229
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/package.json +1 -1
- package/sequence/index.js +46 -40
- package/sequence/test.js +45 -1
package/package.json
CHANGED
package/sequence/index.js
CHANGED
|
@@ -19,7 +19,7 @@ const op = require('../function/operator')
|
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* @template T
|
|
22
|
-
* @typedef { readonly[Sequence<T>, Sequence<T>]
|
|
22
|
+
* @typedef { readonly[Sequence<T>, Sequence<T>]} Concat<T>
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
25
|
/**
|
|
@@ -34,6 +34,12 @@ const op = require('../function/operator')
|
|
|
34
34
|
|
|
35
35
|
const empty = () => undefined
|
|
36
36
|
|
|
37
|
+
/** @type {<T>(first: T) => (tail: Sequence<T>) => Sequence<T>} */
|
|
38
|
+
const create = first => tail => () => ({ first, tail })
|
|
39
|
+
|
|
40
|
+
/** @type {<T>(sequence: Sequence<T>) => Node<T>} */
|
|
41
|
+
const nodeOne = sequence => [empty, sequence]
|
|
42
|
+
|
|
37
43
|
/** @type {<T>(array: readonly T[]) => Result<T>} */
|
|
38
44
|
const fromArray = array => {
|
|
39
45
|
/** @typedef {typeof array extends readonly(infer T)[] ? T : never} T */
|
|
@@ -48,27 +54,23 @@ const fromArray = array => {
|
|
|
48
54
|
/** @type {<T>(sequence: Sequence<T>) => Node<T>} */
|
|
49
55
|
const node = sequence => sequence instanceof Array ? fromArray(sequence) : sequence()
|
|
50
56
|
|
|
51
|
-
/** @type {<T>(concat: Concat<T>) => Sequence<T>} */
|
|
52
|
-
const concatNext = ([a, b]) => {
|
|
53
|
-
const result = node(a)
|
|
54
|
-
if (result === undefined) {
|
|
55
|
-
return b
|
|
56
|
-
} else if (result instanceof Array) {
|
|
57
|
-
const [aa, ab] = result
|
|
58
|
-
return () => [aa, () => [ab, b]]
|
|
59
|
-
} else {
|
|
60
|
-
const { first, tail } = result
|
|
61
|
-
return () => ({ first, tail: () => [tail, b] })
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
57
|
/** @type {<T>(sequence: Sequence<T>) => Result<T>} */
|
|
66
58
|
const next = sequence => {
|
|
67
59
|
let i = sequence
|
|
68
60
|
while (true) {
|
|
69
61
|
const n = node(i)
|
|
70
62
|
if (!(n instanceof Array)) { return n }
|
|
71
|
-
|
|
63
|
+
const [a, b] = n
|
|
64
|
+
const result = node(a)
|
|
65
|
+
if (result === undefined) {
|
|
66
|
+
i = b
|
|
67
|
+
} else if (result instanceof Array) {
|
|
68
|
+
const [aa, ab] = result
|
|
69
|
+
i = () => [aa, () => [ab, b]]
|
|
70
|
+
} else {
|
|
71
|
+
const { first, tail } = result
|
|
72
|
+
return { first, tail: () => [tail, b] }
|
|
73
|
+
}
|
|
72
74
|
}
|
|
73
75
|
}
|
|
74
76
|
|
|
@@ -121,7 +123,7 @@ const flatMap = f => compose(map(f))(flat)
|
|
|
121
123
|
/** @type {<T>(f: (value: T) => boolean) => (result: ResultOne<T>) => Node<T>} */
|
|
122
124
|
const filterFn = f => ({ first, tail }) => {
|
|
123
125
|
const fTail = filter(f)(tail)
|
|
124
|
-
return f(first) ? { first, tail: fTail } : fTail
|
|
126
|
+
return f(first) ? { first, tail: fTail } : nodeOne(fTail)
|
|
125
127
|
}
|
|
126
128
|
|
|
127
129
|
/** @type {<T>(f: (value: T) => boolean) => (input: Sequence<T>) => Thunk<T>} */
|
|
@@ -131,32 +133,26 @@ const filter = f => nextMap(filterFn(f))
|
|
|
131
133
|
const filterMapFn = f => ({first, tail}) => {
|
|
132
134
|
const fFirst = f(first)
|
|
133
135
|
const fTail = filterMap(f)(tail)
|
|
134
|
-
return fFirst === undefined ? fTail
|
|
136
|
+
return fFirst === undefined ? nodeOne(fTail) : { first: fFirst, tail: fTail }
|
|
135
137
|
}
|
|
136
138
|
|
|
137
139
|
/** @type {<I, O>(f: (value: I) => O|undefined) => (input: Sequence<I>) => Thunk<O>} */
|
|
138
140
|
const filterMap = f => nextMap(filterMapFn(f))
|
|
139
141
|
|
|
142
|
+
/** @type {<T>(f: (value: T) => boolean) => (result: ResultOne<T>) => Node<T>} */
|
|
143
|
+
const takeWhileFn = f => ({ first, tail }) => f(first) ? { first, tail: takeWhile(f)(tail) } :undefined
|
|
144
|
+
|
|
140
145
|
/** @type {<T>(f: (value: T) => boolean) => (input: Sequence<T>) => Thunk<T>} */
|
|
141
|
-
const takeWhile = f =>
|
|
142
|
-
|
|
143
|
-
|
|
146
|
+
const takeWhile = f => nextMap(takeWhileFn(f))
|
|
147
|
+
|
|
148
|
+
/** @type {<T>(f: (value: T) => boolean) => (result: ResultOne<T>) => Node<T>} */
|
|
149
|
+
const dropWhileFn = f => result => {
|
|
144
150
|
const { first, tail } = result
|
|
145
|
-
|
|
146
|
-
return { first, tail: takeWhile(f)(result.tail) }
|
|
151
|
+
return f(first) ? nodeOne(dropWhile(f)(tail)) : result
|
|
147
152
|
}
|
|
148
153
|
|
|
149
154
|
/** @type {<T>(f: (value: T) => boolean) => (input: Sequence<T>) => Thunk<T>} */
|
|
150
|
-
const dropWhile = f =>
|
|
151
|
-
let i = input
|
|
152
|
-
while (true) {
|
|
153
|
-
const result = next(i)
|
|
154
|
-
if (result === undefined) { return undefined }
|
|
155
|
-
const { first, tail } = result
|
|
156
|
-
if (!f(first)) return result
|
|
157
|
-
i = tail
|
|
158
|
-
}
|
|
159
|
-
}
|
|
155
|
+
const dropWhile = f => nextMap(dropWhileFn(f))
|
|
160
156
|
|
|
161
157
|
/** @type {<D>(def: D) => <T>(input: Sequence<T>) => D|T} */
|
|
162
158
|
const first = def => input => {
|
|
@@ -210,15 +206,15 @@ const countdown = count => () => {
|
|
|
210
206
|
* @typedef {readonly[A, ScanFunc<T, A>]} ScanState
|
|
211
207
|
*/
|
|
212
208
|
|
|
213
|
-
/** @type {<T,A>(operator: ScanFunc<T, A>) => (
|
|
214
|
-
const
|
|
215
|
-
const
|
|
216
|
-
|
|
217
|
-
const { first, tail } = result
|
|
218
|
-
const r = operator(first)
|
|
219
|
-
return { first: r[0], tail: scan(r[1])(tail) }
|
|
209
|
+
/** @type {<T,A>(operator: ScanFunc<T, A>) => (result: ResultOne<T>) => Node<A>} */
|
|
210
|
+
const scanFn = operator => ({first, tail}) => {
|
|
211
|
+
const [value, nextOperator] = operator(first)
|
|
212
|
+
return { first: value, tail: scan(nextOperator)(tail) }
|
|
220
213
|
}
|
|
221
214
|
|
|
215
|
+
/** @type {<T,A>(operator: ScanFunc<T, A>) => (input: Sequence<T>) => Thunk<A>} */
|
|
216
|
+
const scan = operator => nextMap(scanFn(operator))
|
|
217
|
+
|
|
222
218
|
/** @type {<T,A>(operator: ScanFunc<T, A>) => <D>(def: D)=> (input: Sequence<T>) => D|A} */
|
|
223
219
|
const scanReduce = operator => def => input => last(def)(scan(operator)(input))
|
|
224
220
|
|
|
@@ -269,6 +265,12 @@ const entryOp = index => value => [[index, value], entryOp(index + 1)]
|
|
|
269
265
|
/** @type {<T>(input: Sequence<T>) => Thunk<Entry<T>>} */
|
|
270
266
|
const entries = scan(entryOp(0))
|
|
271
267
|
|
|
268
|
+
/** @type {<T>(prior: Sequence<T>) => (value: T) => Sequence<T>} */
|
|
269
|
+
const reverseOp = prior => value => create(value)(prior)
|
|
270
|
+
|
|
271
|
+
/** @type {<T>(input: Sequence<T>) => Sequence<T>} */
|
|
272
|
+
const reverse = reduce(reverseOp)(empty)
|
|
273
|
+
|
|
272
274
|
module.exports = {
|
|
273
275
|
/** @readonly */
|
|
274
276
|
empty,
|
|
@@ -293,6 +295,8 @@ module.exports = {
|
|
|
293
295
|
/** @readonly */
|
|
294
296
|
filter,
|
|
295
297
|
/** @readonly */
|
|
298
|
+
filterMap,
|
|
299
|
+
/** @readonly */
|
|
296
300
|
find,
|
|
297
301
|
/** @readonly */
|
|
298
302
|
some,
|
|
@@ -323,5 +327,7 @@ module.exports = {
|
|
|
323
327
|
/** @readonly */
|
|
324
328
|
length,
|
|
325
329
|
/** @readonly */
|
|
330
|
+
reverse,
|
|
331
|
+
/** @readonly */
|
|
326
332
|
countdown,
|
|
327
333
|
}
|
package/sequence/test.js
CHANGED
|
@@ -92,9 +92,31 @@ const stringify = sequence => json.stringify(sort)(_.toArray(sequence))
|
|
|
92
92
|
if (result !== '[[0,"hello"],[1,"world"]]') { throw result }
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
+
{
|
|
96
|
+
const result = stringify(_.reverse([]))
|
|
97
|
+
if (result !== '[]') { throw result }
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
{
|
|
101
|
+
const result = stringify(_.reverse([1,2,3,4,5]))
|
|
102
|
+
if (result !== '[5,4,3,2,1]') { throw result }
|
|
103
|
+
}
|
|
104
|
+
|
|
95
105
|
// stress tests
|
|
96
106
|
|
|
97
107
|
const stress = () => {
|
|
108
|
+
|
|
109
|
+
{
|
|
110
|
+
// 100_000_000 is too much
|
|
111
|
+
const n = 50_000_000
|
|
112
|
+
const result = _.toArray(_.countdown(n))
|
|
113
|
+
if (result.length !== n) { throw result.length }
|
|
114
|
+
const len = _.length(_.filter(x => x > n)(result))
|
|
115
|
+
if (len !== 0) { throw len }
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
console.log('first')
|
|
119
|
+
|
|
98
120
|
{
|
|
99
121
|
// 200_000_000 is too much
|
|
100
122
|
const n = 100_000_000
|
|
@@ -133,9 +155,31 @@ const stress = () => {
|
|
|
133
155
|
}
|
|
134
156
|
const a = _.next(sequence)
|
|
135
157
|
}
|
|
158
|
+
|
|
159
|
+
console.log('filterMap')
|
|
160
|
+
|
|
161
|
+
{
|
|
162
|
+
// 100_000_000 is too much
|
|
163
|
+
const n = 50_000_000
|
|
164
|
+
const result = _.toArray(_.countdown(n))
|
|
165
|
+
if (result.length !== n) { throw result.length }
|
|
166
|
+
const len = _.length(_.filterMap(() => undefined)(result))
|
|
167
|
+
if (len !== 0) { throw len }
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
console.log('dropWhile')
|
|
171
|
+
|
|
172
|
+
{
|
|
173
|
+
// 50_000_000 is too much
|
|
174
|
+
const n = 20_000_000
|
|
175
|
+
const result = _.toArray(_.countdown(n))
|
|
176
|
+
if (result.length !== n) { throw result.length }
|
|
177
|
+
const len = _.length(_.dropWhile(() => true)(result))
|
|
178
|
+
if (len !== 0) { throw len }
|
|
179
|
+
}
|
|
136
180
|
}
|
|
137
181
|
|
|
138
|
-
stress()
|
|
182
|
+
// stress()
|
|
139
183
|
|
|
140
184
|
module.exports = {
|
|
141
185
|
|