functionalscript 0.0.219 → 0.0.227
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/README.md +1 -1
- package/package.json +1 -1
- package/sequence/index.js +67 -57
- package/sequence/test.js +24 -1
package/README.md
CHANGED
package/package.json
CHANGED
package/sequence/index.js
CHANGED
|
@@ -19,16 +19,24 @@ 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
|
/**
|
|
26
26
|
* @template T
|
|
27
|
-
* @typedef { undefined |
|
|
27
|
+
* @typedef { undefined | ResultOne<T> } Result
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @template T
|
|
32
|
+
* @typedef {{ readonly first: T, readonly tail: Sequence<T> }} ResultOne
|
|
28
33
|
*/
|
|
29
34
|
|
|
30
35
|
const empty = () => undefined
|
|
31
36
|
|
|
37
|
+
/** @type {<T>(sequence: Sequence<T>) => Node<T>} */
|
|
38
|
+
const nodeOne = sequence => [empty, sequence]
|
|
39
|
+
|
|
32
40
|
/** @type {<T>(array: readonly T[]) => Result<T>} */
|
|
33
41
|
const fromArray = array => {
|
|
34
42
|
/** @typedef {typeof array extends readonly(infer T)[] ? T : never} T */
|
|
@@ -43,27 +51,23 @@ const fromArray = array => {
|
|
|
43
51
|
/** @type {<T>(sequence: Sequence<T>) => Node<T>} */
|
|
44
52
|
const node = sequence => sequence instanceof Array ? fromArray(sequence) : sequence()
|
|
45
53
|
|
|
46
|
-
/** @type {<T>(concat: Concat<T>) => Sequence<T>} */
|
|
47
|
-
const concatNext = ([a, b]) => {
|
|
48
|
-
const result = node(a)
|
|
49
|
-
if (result === undefined) {
|
|
50
|
-
return b
|
|
51
|
-
} else if (result instanceof Array) {
|
|
52
|
-
const [aa, ab] = result
|
|
53
|
-
return () => [aa, () => [ab, b]]
|
|
54
|
-
} else {
|
|
55
|
-
const { first, tail } = result
|
|
56
|
-
return () => ({ first, tail: () => [tail, b] })
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
54
|
/** @type {<T>(sequence: Sequence<T>) => Result<T>} */
|
|
61
55
|
const next = sequence => {
|
|
62
56
|
let i = sequence
|
|
63
57
|
while (true) {
|
|
64
58
|
const n = node(i)
|
|
65
59
|
if (!(n instanceof Array)) { return n }
|
|
66
|
-
|
|
60
|
+
const [a, b] = n
|
|
61
|
+
const result = node(a)
|
|
62
|
+
if (result === undefined) {
|
|
63
|
+
i = b
|
|
64
|
+
} else if (result instanceof Array) {
|
|
65
|
+
const [aa, ab] = result
|
|
66
|
+
i = () => [aa, () => [ab, b]]
|
|
67
|
+
} else {
|
|
68
|
+
const { first, tail } = result
|
|
69
|
+
return { first, tail: () => [tail, b] }
|
|
70
|
+
}
|
|
67
71
|
}
|
|
68
72
|
}
|
|
69
73
|
|
|
@@ -73,15 +77,11 @@ const iterable = sequence => ({
|
|
|
73
77
|
let i = sequence
|
|
74
78
|
while (true) {
|
|
75
79
|
if (i instanceof Array) { return yield *i }
|
|
76
|
-
const n =
|
|
80
|
+
const n = next(i)
|
|
77
81
|
if (n === undefined) { return }
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const { first, tail } = n
|
|
82
|
-
yield first
|
|
83
|
-
i = tail
|
|
84
|
-
}
|
|
82
|
+
const { first, tail } = n
|
|
83
|
+
yield first
|
|
84
|
+
i = tail
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
87
|
})
|
|
@@ -92,47 +92,50 @@ const toArray = sequence => {
|
|
|
92
92
|
return Array.from(iterable(sequence))
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
/** @type {<
|
|
96
|
-
const
|
|
97
|
-
const n = next(
|
|
95
|
+
/** @type {<I, O>(f: (result: ResultOne<I>) => Node<O>) => (input: Sequence<I>) => Thunk<O>} */
|
|
96
|
+
const nextMap = f => input => () => {
|
|
97
|
+
const n = next(input)
|
|
98
98
|
if (n === undefined) { return undefined }
|
|
99
|
-
|
|
100
|
-
return [first, flat(tail)]
|
|
99
|
+
return f(n)
|
|
101
100
|
}
|
|
102
101
|
|
|
102
|
+
/** @type {<T>(result: ResultOne<Sequence<T>>) => Node<T>} */
|
|
103
|
+
const flatFn = ({first, tail}) => [first, flat(tail)]
|
|
104
|
+
|
|
105
|
+
/** @type {<T>(sequence: Sequence<Sequence<T>>) => Thunk<T>} */
|
|
106
|
+
const flat = nextMap(flatFn)
|
|
107
|
+
|
|
103
108
|
/** @type {<T>(...array: readonly Sequence<T>[]) => Thunk<T>} */
|
|
104
109
|
const concat = (...array) => flat(array)
|
|
105
110
|
|
|
111
|
+
/** @type {<I, O>(f: (value: I) => O) => (result: ResultOne<I>) => Node<O>} */
|
|
112
|
+
const mapFn = f => ({ first, tail }) => ({ first: f(first), tail: map(f)(tail) })
|
|
113
|
+
|
|
106
114
|
/** @type {<I, O>(f: (value: I) => O) => (input: Sequence<I>) => Thunk<O>} */
|
|
107
|
-
const map = f =>
|
|
108
|
-
const n = next(sequence)
|
|
109
|
-
if (n === undefined) { return undefined }
|
|
110
|
-
const { first, tail } = n
|
|
111
|
-
return { first: f(first), tail: map(f)(tail) }
|
|
112
|
-
}
|
|
115
|
+
const map = f => nextMap(mapFn(f))
|
|
113
116
|
|
|
114
117
|
/** @type {<I, O>(f: (value: I) => Sequence<O>) => (input: Sequence<I>) => Thunk<O>} */
|
|
115
|
-
const flatMap = f =>
|
|
118
|
+
const flatMap = f => compose(map(f))(flat)
|
|
116
119
|
|
|
117
|
-
/** @type {<T>(f: (value: T) => boolean) => (
|
|
118
|
-
const
|
|
119
|
-
const n = next(sequence)
|
|
120
|
-
if (n === undefined) { return undefined }
|
|
121
|
-
const { first, tail } = n
|
|
120
|
+
/** @type {<T>(f: (value: T) => boolean) => (result: ResultOne<T>) => Node<T>} */
|
|
121
|
+
const filterFn = f => ({ first, tail }) => {
|
|
122
122
|
const fTail = filter(f)(tail)
|
|
123
|
-
return f(first) ? { first, tail: fTail } : fTail
|
|
123
|
+
return f(first) ? { first, tail: fTail } : nodeOne(fTail)
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
-
/** @type {<
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
126
|
+
/** @type {<T>(f: (value: T) => boolean) => (input: Sequence<T>) => Thunk<T>} */
|
|
127
|
+
const filter = f => nextMap(filterFn(f))
|
|
128
|
+
|
|
129
|
+
/** @type {<I, O>(f: (value: I) => O|undefined) => (result: ResultOne<I>) => Node<O>} */
|
|
130
|
+
const filterMapFn = f => ({first, tail}) => {
|
|
131
131
|
const fFirst = f(first)
|
|
132
132
|
const fTail = filterMap(f)(tail)
|
|
133
|
-
return fFirst === undefined ? fTail
|
|
133
|
+
return fFirst === undefined ? nodeOne(fTail) : { first: fFirst, tail: fTail }
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
+
/** @type {<I, O>(f: (value: I) => O|undefined) => (input: Sequence<I>) => Thunk<O>} */
|
|
137
|
+
const filterMap = f => nextMap(filterMapFn(f))
|
|
138
|
+
|
|
136
139
|
/** @type {<T>(f: (value: T) => boolean) => (input: Sequence<T>) => Thunk<T>} */
|
|
137
140
|
const takeWhile = f => input => () => {
|
|
138
141
|
const result = next(input)
|
|
@@ -144,14 +147,11 @@ const takeWhile = f => input => () => {
|
|
|
144
147
|
|
|
145
148
|
/** @type {<T>(f: (value: T) => boolean) => (input: Sequence<T>) => Thunk<T>} */
|
|
146
149
|
const dropWhile = f => input => () => {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
if (!f(first)) return result
|
|
153
|
-
i = tail
|
|
154
|
-
}
|
|
150
|
+
const result = next(input)
|
|
151
|
+
if (result === undefined) { return undefined }
|
|
152
|
+
const { first, tail } = result
|
|
153
|
+
if (f(first)) { return nodeOne(dropWhile(f)(tail)) }
|
|
154
|
+
return result
|
|
155
155
|
}
|
|
156
156
|
|
|
157
157
|
/** @type {<D>(def: D) => <T>(input: Sequence<T>) => D|T} */
|
|
@@ -248,6 +248,12 @@ const sum = fold(addition)(0)
|
|
|
248
248
|
/** @type {(separator: string) => (input: Sequence<string>) => string} */
|
|
249
249
|
const join = separator => fold(op.join(separator))('')
|
|
250
250
|
|
|
251
|
+
/** @type {(a: number) => () => number} */
|
|
252
|
+
const counter = a => () => a + 1
|
|
253
|
+
|
|
254
|
+
/** @type {<T>(input: Sequence<T>) => number} */
|
|
255
|
+
const length = reduce(counter)(0)
|
|
256
|
+
|
|
251
257
|
/**
|
|
252
258
|
* @template T
|
|
253
259
|
* @typedef {readonly[number, T]} Entry
|
|
@@ -283,6 +289,8 @@ module.exports = {
|
|
|
283
289
|
/** @readonly */
|
|
284
290
|
filter,
|
|
285
291
|
/** @readonly */
|
|
292
|
+
filterMap,
|
|
293
|
+
/** @readonly */
|
|
286
294
|
find,
|
|
287
295
|
/** @readonly */
|
|
288
296
|
some,
|
|
@@ -311,5 +319,7 @@ module.exports = {
|
|
|
311
319
|
/** @readonly */
|
|
312
320
|
entries,
|
|
313
321
|
/** @readonly */
|
|
322
|
+
length,
|
|
323
|
+
/** @readonly */
|
|
314
324
|
countdown,
|
|
315
325
|
}
|
package/sequence/test.js
CHANGED
|
@@ -95,6 +95,18 @@ const stringify = sequence => json.stringify(sort)(_.toArray(sequence))
|
|
|
95
95
|
// stress tests
|
|
96
96
|
|
|
97
97
|
const stress = () => {
|
|
98
|
+
|
|
99
|
+
{
|
|
100
|
+
// 100_000_000 is too much
|
|
101
|
+
const n = 50_000_000
|
|
102
|
+
const result = _.toArray(_.countdown(n))
|
|
103
|
+
if (result.length !== n) { throw result.length }
|
|
104
|
+
const len = _.length(_.filter(x => x > n)(result))
|
|
105
|
+
if (len !== 0) { throw len }
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
console.log('first')
|
|
109
|
+
|
|
98
110
|
{
|
|
99
111
|
// 200_000_000 is too much
|
|
100
112
|
const n = 100_000_000
|
|
@@ -133,9 +145,20 @@ const stress = () => {
|
|
|
133
145
|
}
|
|
134
146
|
const a = _.next(sequence)
|
|
135
147
|
}
|
|
148
|
+
|
|
149
|
+
console.log('filterMap')
|
|
150
|
+
|
|
151
|
+
{
|
|
152
|
+
// 100_000_000 is too much
|
|
153
|
+
const n = 50_000_000
|
|
154
|
+
const result = _.toArray(_.countdown(n))
|
|
155
|
+
if (result.length !== n) { throw result.length }
|
|
156
|
+
const len = _.length(_.filterMap(() => undefined)(result))
|
|
157
|
+
if (len !== 0) { throw len }
|
|
158
|
+
}
|
|
136
159
|
}
|
|
137
160
|
|
|
138
|
-
//stress()
|
|
161
|
+
// stress()
|
|
139
162
|
|
|
140
163
|
module.exports = {
|
|
141
164
|
|