functionalscript 0.0.212 → 0.0.217
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/function/index.js +2 -2
- package/json/test.js +4 -4
- package/package.json +1 -1
- package/sequence/index.js +28 -9
- package/sequence/operator/README.md +41 -0
- package/sequence/test.js +34 -24
package/function/index.js
CHANGED
package/json/test.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const json = require('.')
|
|
2
2
|
const { sort } = require('../object')
|
|
3
|
-
const {
|
|
3
|
+
const { identity } = require('../function')
|
|
4
4
|
|
|
5
5
|
if (json.addProperty("Hello")([])({}) !== "Hello") { throw 'error' }
|
|
6
6
|
|
|
@@ -10,7 +10,7 @@ if (json.addProperty("Hello")([])({}) !== "Hello") { throw 'error' }
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
{
|
|
13
|
-
const x = json.stringify(
|
|
13
|
+
const x = json.stringify(identity)(json.addProperty("Hello")(['a'])({}))
|
|
14
14
|
if (x !== '{"a":"Hello"}') { throw x }
|
|
15
15
|
}
|
|
16
16
|
|
|
@@ -20,7 +20,7 @@ if (json.addProperty("Hello")([])({}) !== "Hello") { throw 'error' }
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
{
|
|
23
|
-
const x = json.stringify(
|
|
23
|
+
const x = json.stringify(identity)(json.addProperty("Hello")(['a'])({ c: [], b: 12 }))
|
|
24
24
|
if (x !== '{"c":[],"b":12,"a":"Hello"}') { throw x }
|
|
25
25
|
}
|
|
26
26
|
|
|
@@ -34,6 +34,6 @@ if (json.addProperty("Hello")([])({}) !== "Hello") { throw 'error' }
|
|
|
34
34
|
{
|
|
35
35
|
const _0 = { a: { y: [24] }, c: [], b: 12 }
|
|
36
36
|
const _1 = json.addProperty("Hello")(['a', 'x'])(_0)
|
|
37
|
-
const _2 = json.stringify(
|
|
37
|
+
const _2 = json.stringify(identity)(_1)
|
|
38
38
|
if (_2 !== '{"a":{"y":[24],"x":"Hello"},"c":[],"b":12}') { throw _2 }
|
|
39
39
|
}
|
package/package.json
CHANGED
package/sequence/index.js
CHANGED
|
@@ -18,7 +18,7 @@ const { logicalNot, strictEqual } = require('../function/operator')
|
|
|
18
18
|
*
|
|
19
19
|
* Please note that the sequence also contains `Concat<T>. We need this as
|
|
20
20
|
* a workaround because modern JavaScript implementations don't support
|
|
21
|
-
* ES6 TCO (Tail Call Optimization). Without this
|
|
21
|
+
* ES6 TCO (Tail Call Optimization). Without this workaround, we may have
|
|
22
22
|
* a stack overflow if a list contains a lot of concateneted lists.
|
|
23
23
|
*
|
|
24
24
|
* @template T
|
|
@@ -37,6 +37,9 @@ const { logicalNot, strictEqual } = require('../function/operator')
|
|
|
37
37
|
|
|
38
38
|
const empty = () => undefined
|
|
39
39
|
|
|
40
|
+
/** @type {<T>(first: T) => (tail: Sequence<T>) => Sequence<T>} */
|
|
41
|
+
const sequence = first => tail => () => [first, tail]
|
|
42
|
+
|
|
40
43
|
/** @type {<F, T>(a: readonly[F, Sequence<T>]) => (b: Sequence<T>) => readonly[F, Sequence<T>]} */
|
|
41
44
|
const norm = ([a0, a1]) => b => [a0, [a1, b]]
|
|
42
45
|
|
|
@@ -78,7 +81,7 @@ const first = input => {
|
|
|
78
81
|
*/
|
|
79
82
|
|
|
80
83
|
/**
|
|
81
|
-
* Note: the operation is not lazy. It
|
|
84
|
+
* Note: the operation is not lazy. It traverses the given array and creates a linked list.
|
|
82
85
|
*
|
|
83
86
|
* @type {<T>(...array: readonly T[]) => Sequence<T>}
|
|
84
87
|
*/
|
|
@@ -86,14 +89,12 @@ const list = (...array) => {
|
|
|
86
89
|
/** @typedef {typeof array extends readonly(infer T)[] ? T : never} T */
|
|
87
90
|
let i = array.length
|
|
88
91
|
/** @type {Sequence<T>} */
|
|
89
|
-
let
|
|
92
|
+
let iResult = empty
|
|
90
93
|
while (i !== 0) {
|
|
91
94
|
i = i - 1
|
|
92
|
-
|
|
93
|
-
const listResult = [array[i], result]
|
|
94
|
-
result = () => listResult
|
|
95
|
+
iResult = sequence(array[i])(iResult)
|
|
95
96
|
}
|
|
96
|
-
return
|
|
97
|
+
return iResult
|
|
97
98
|
}
|
|
98
99
|
|
|
99
100
|
/** @type {<T>(...array: readonly Sequence<T>[]) => Sequence<T>} */
|
|
@@ -184,8 +185,8 @@ const last = def => input => {
|
|
|
184
185
|
/** @type {<T, R>(s: seqOp.ExclusiveScan<T, R>) => (input: Sequence<T>) => R} */
|
|
185
186
|
const reduce = ([first, s]) => input => last(first)(scan(s)(input))
|
|
186
187
|
|
|
187
|
-
/** @type {<T, R>(
|
|
188
|
-
const fold =
|
|
188
|
+
/** @type {<T, R>(operator: op.ReduceOperator<R, T>) => (first: R) => (input: Sequence<T>) => R} */
|
|
189
|
+
const fold = operator => first => reduce(seqOp.exclusiveScan(operator)(first))
|
|
189
190
|
|
|
190
191
|
const entries = scan(seqOp.entries)
|
|
191
192
|
|
|
@@ -265,6 +266,20 @@ const zip = a => b => () => {
|
|
|
265
266
|
return [[resultA[0], resultB[0]], zip(resultA[1])(resultB[1])]
|
|
266
267
|
}
|
|
267
268
|
|
|
269
|
+
/** @type {<T>(s: Sequence<T>) => Sequence<T>} */
|
|
270
|
+
const reverse = s => {
|
|
271
|
+
/** @type {typeof s} */
|
|
272
|
+
let iResult = empty
|
|
273
|
+
let iSource = s
|
|
274
|
+
while (true) {
|
|
275
|
+
const result = next(iSource)
|
|
276
|
+
if (result === undefined) { return iResult }
|
|
277
|
+
const [first, tail] = result
|
|
278
|
+
iResult = sequence(first)(iResult)
|
|
279
|
+
iSource = tail
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
268
283
|
module.exports = {
|
|
269
284
|
/** @readonly */
|
|
270
285
|
next,
|
|
@@ -273,6 +288,8 @@ module.exports = {
|
|
|
273
288
|
/** @readonly */
|
|
274
289
|
empty,
|
|
275
290
|
/** @readonly */
|
|
291
|
+
sequence,
|
|
292
|
+
/** @readonly */
|
|
276
293
|
at,
|
|
277
294
|
/** @readonly */
|
|
278
295
|
concat,
|
|
@@ -326,4 +343,6 @@ module.exports = {
|
|
|
326
343
|
includes,
|
|
327
344
|
/** @readonly */
|
|
328
345
|
zip,
|
|
346
|
+
/** @readonly */
|
|
347
|
+
reverse,
|
|
329
348
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Operator
|
|
2
|
+
|
|
3
|
+
## Sequence
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
type Sequence<T> = SubSequence<T, undefined>
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## SubSequence
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
type SubSequence<T, C> = () => SubSequenceResult<T, C>
|
|
13
|
+
type SubSequenceResult<T, C> = [T, SubSequence<T, C>] | [C]
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## The Main FlatScan Operator
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
type FlatScanOperator<T, A> = (value: T) => SubSequence<A, FlatScanOp<T, A>>
|
|
20
|
+
|
|
21
|
+
const flatScanConcat
|
|
22
|
+
: SubSequence<A, FlatScanOp<T, A>> => Sequence<T> => Sequence<A>
|
|
23
|
+
=> a => b => () => {
|
|
24
|
+
switch (next(a)) {
|
|
25
|
+
case [first, tail]: { return [first, flatScanConcat(tail)(b)] }
|
|
26
|
+
case [operator]: { return flatScan(operator)(b)() }
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const flatScan
|
|
31
|
+
: FlatScanOperator<T, A> => Sequence<T> => Sequence<A>
|
|
32
|
+
=> operator => sequence => () => {
|
|
33
|
+
// optimization for `takeWhile`, `find`
|
|
34
|
+
if (operator === flatScanEmpty) { return [undefined] }
|
|
35
|
+
//
|
|
36
|
+
switch (next(s)) {
|
|
37
|
+
case [first, tail]: { return flatScanConcat(operator(first))(tail)() }
|
|
38
|
+
case [undefined]: { return [undefined] }
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
```
|
package/sequence/test.js
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
const seq = require('.')
|
|
2
|
+
const { empty, next, list, flatMap, concat, exclusiveScan, find, every, some, first, drop, map, generate } = require('.')
|
|
2
3
|
const { sum } = require('./operator')
|
|
3
4
|
const array = require('./array')
|
|
5
|
+
const json = require('../json')
|
|
6
|
+
const { identity } = require('../function')
|
|
4
7
|
|
|
5
8
|
/** @type {<T>(input: seq.Sequence<T>) => void} */
|
|
6
9
|
const print = input => {
|
|
7
10
|
let i = input
|
|
8
11
|
while (true) {
|
|
9
|
-
const result =
|
|
12
|
+
const result = next(i)
|
|
10
13
|
if (result === undefined) { return }
|
|
11
14
|
console.log(result[0])
|
|
12
15
|
i = result[1]
|
|
@@ -14,47 +17,47 @@ const print = input => {
|
|
|
14
17
|
}
|
|
15
18
|
|
|
16
19
|
{
|
|
17
|
-
const big =
|
|
18
|
-
const list0 =
|
|
19
|
-
const list1 =
|
|
20
|
-
const list2 =
|
|
21
|
-
const list3 =
|
|
22
|
-
const r =
|
|
23
|
-
if (
|
|
24
|
-
if (
|
|
25
|
-
if (
|
|
26
|
-
if (
|
|
27
|
-
if (
|
|
20
|
+
const big = list(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 42, 60)
|
|
21
|
+
const list0 = list(0, 1, 2, 3)
|
|
22
|
+
const list1 = flatMap(x => list(x, x * 2, x * 3))(list0)
|
|
23
|
+
const list2 = concat(list0, list0)
|
|
24
|
+
const list3 = exclusiveScan(sum)(list0)
|
|
25
|
+
const r = find(x => x === 42)(big)
|
|
26
|
+
if (every(x => x > 0)(big) !== true) { throw 'x' }
|
|
27
|
+
if (every(x => x < 20)(big) !== false) { throw 'x' }
|
|
28
|
+
if (some(x => x > 100)(big) !== false) { throw 'x' }
|
|
29
|
+
if (some(x => x > 50)(big) !== true) { throw 'x' }
|
|
30
|
+
if (first(drop(16)(big)) !== 42) { throw 'drop' }
|
|
28
31
|
{
|
|
29
|
-
const a =
|
|
32
|
+
const a = map(generate)(generate(100_000))
|
|
30
33
|
const ar = array.fromSequence(a)
|
|
31
|
-
// This operation
|
|
34
|
+
// This operation uses a lot of stack because `...`
|
|
32
35
|
// puts array items on a stack.
|
|
33
36
|
// Use `array.sequence` instead
|
|
34
|
-
const x =
|
|
35
|
-
const r =
|
|
37
|
+
const x = concat(...ar)
|
|
38
|
+
const r = next(x)
|
|
36
39
|
// print(x)
|
|
37
40
|
}
|
|
38
41
|
{
|
|
39
|
-
const a = array.fromSequence(
|
|
40
|
-
let x =
|
|
41
|
-
const r =
|
|
42
|
+
const a = array.fromSequence(generate(1_000_000))
|
|
43
|
+
let x = concat(array.sequence(a), big)
|
|
44
|
+
const r = next(x)
|
|
42
45
|
// print(x)
|
|
43
46
|
}
|
|
44
47
|
{
|
|
45
48
|
let x = big
|
|
46
49
|
for (let i = 0; i < 1_000_000; ++i) {
|
|
47
|
-
x =
|
|
50
|
+
x = concat(empty, x)
|
|
48
51
|
}
|
|
49
|
-
const r =
|
|
52
|
+
const r = next(x)
|
|
50
53
|
// print(x)
|
|
51
|
-
}
|
|
54
|
+
}
|
|
52
55
|
{
|
|
53
56
|
let x = big
|
|
54
57
|
for (let i = 0; i < 1_000_000; ++i) {
|
|
55
|
-
x =
|
|
58
|
+
x = concat(x, list(i))
|
|
56
59
|
}
|
|
57
|
-
const r =
|
|
60
|
+
const r = next(x)
|
|
58
61
|
// print(x)
|
|
59
62
|
}
|
|
60
63
|
}
|
|
@@ -63,3 +66,10 @@ const print = input => {
|
|
|
63
66
|
const x = seq.join(':')(seq.list("1", "2", "3", "4", "5", "6"))
|
|
64
67
|
if (x !== "1:2:3:4:5:6") { throw x }
|
|
65
68
|
}
|
|
69
|
+
|
|
70
|
+
{
|
|
71
|
+
const r = seq.reverse(seq.list(1, 2, 3, 4))
|
|
72
|
+
const s = array.fromSequence(r)
|
|
73
|
+
const j = json.stringify(identity)(s)
|
|
74
|
+
if (j !== '[4,3,2,1]') { throw j }
|
|
75
|
+
}
|