functionalscript 0.0.178 → 0.0.185
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 +3 -0
- package/btree/index.js +1 -1
- package/btree/test.js +3 -2
- package/function/operator/index.js +25 -2
- package/map/index.js +6 -5
- package/map/test.js +2 -1
- package/module-manager/index.js +2 -2
- package/package.json +1 -1
- package/sequence/README.md +2 -2
- package/sequence/array/index.js +7 -0
- package/sequence/asyncIterable/index.js +4 -4
- package/sequence/index.js +12 -10
- package/sequence/iterable/index.js +4 -4
- package/sequence/list/index.js +176 -65
- package/sequence/list/test.js +19 -12
package/README.md
CHANGED
|
@@ -10,6 +10,9 @@ Try FunctionalScript [here](https://functionalscript.com/).
|
|
|
10
10
|
|
|
11
11
|
Create a new FunctionalScript repository on GitHub [here](https://github.com/functionalscript/template/generate).
|
|
12
12
|
|
|
13
|
+
One of the main challenges is how to make a pure functional language when ES6 TCO is not supported by Chrome and Firefox.
|
|
14
|
+
A workaround for this problem is to use `let` for renaming objects.
|
|
15
|
+
|
|
13
16
|
## JSON
|
|
14
17
|
|
|
15
18
|
```js
|
package/btree/index.js
CHANGED
package/btree/test.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const btree = require('.')
|
|
2
2
|
const { setVisitor, valuesList } = btree
|
|
3
3
|
const { cmp } = require('../cmp')
|
|
4
|
+
const list = require('../sequence/list')
|
|
4
5
|
|
|
5
6
|
/** @type {(node: btree.Node<string>) => (value: string) => btree.Node<string>} */
|
|
6
7
|
const set = node => value => {
|
|
@@ -21,11 +22,11 @@ const test = () => {
|
|
|
21
22
|
//
|
|
22
23
|
{
|
|
23
24
|
/** @type {import('../sequence/list').Result<string>} */
|
|
24
|
-
let result = valuesList(node)
|
|
25
|
+
let result = list.next(valuesList(node))
|
|
25
26
|
while (result !== undefined) {
|
|
26
27
|
const t = result[0]
|
|
27
28
|
console.log(t)
|
|
28
|
-
result = result[1]
|
|
29
|
+
result = list.next(result[1])
|
|
29
30
|
}
|
|
30
31
|
}
|
|
31
32
|
}
|
|
@@ -1,18 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @template A
|
|
3
|
+
* @template B
|
|
4
|
+
* @template R
|
|
5
|
+
* @typedef {(a: A) => (b: B) => R} BinaryOperator
|
|
6
|
+
*/
|
|
7
|
+
|
|
1
8
|
/**
|
|
2
9
|
* @template R
|
|
3
10
|
* @template T
|
|
4
|
-
* @typedef {
|
|
11
|
+
* @typedef {BinaryOperator<R, T, R>} ReduceOperator
|
|
5
12
|
*/
|
|
6
13
|
|
|
7
|
-
/** @type {(separator: string) =>
|
|
14
|
+
/** @type {(separator: string) => ReduceOperator<string, string>} */
|
|
8
15
|
const join = separator => prior => value => `${prior}${separator}${value}`
|
|
9
16
|
|
|
10
17
|
/** @type {(sum: number) => (value: number) => number} */
|
|
11
18
|
const addition = a => b => a + b
|
|
12
19
|
|
|
20
|
+
/**
|
|
21
|
+
* @template T
|
|
22
|
+
* @template R
|
|
23
|
+
* @typedef {(value: T) => R} UnaryOperator
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/** @type {(value: boolean) => boolean} */
|
|
27
|
+
const logicalNot = v => !v
|
|
28
|
+
|
|
29
|
+
/** @type {<T>(a: T) => (b: T) => boolean} */
|
|
30
|
+
const strictEqual = a => b => a === b
|
|
31
|
+
|
|
13
32
|
module.exports = {
|
|
14
33
|
/** @readonly */
|
|
15
34
|
join,
|
|
16
35
|
/** @readonly */
|
|
17
36
|
addition,
|
|
37
|
+
/** @readonly */
|
|
38
|
+
strictEqual,
|
|
39
|
+
/** @readonly */
|
|
40
|
+
logicalNot,
|
|
18
41
|
}
|
package/map/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const option = require("../option")
|
|
2
|
-
const { getVisitor, setVisitor,
|
|
2
|
+
const { getVisitor, setVisitor, valuesList } = require("../btree")
|
|
3
3
|
const { cmp } = require("../cmp")
|
|
4
|
+
const list = require("../sequence/list")
|
|
4
5
|
|
|
5
6
|
/** @typedef {import("../cmp").Sign} Sign */
|
|
6
7
|
|
|
@@ -29,7 +30,7 @@ const { cmp } = require("../cmp")
|
|
|
29
30
|
* @typedef {{
|
|
30
31
|
* readonly get: (name: string) => T|undefined
|
|
31
32
|
* readonly set: (name: string) => (value: T) => Map<T>
|
|
32
|
-
* readonly entries:
|
|
33
|
+
* readonly entries: list.List<Entry<T>>
|
|
33
34
|
* readonly root: undefined|TNode<Entry<T>>
|
|
34
35
|
* }} Map
|
|
35
36
|
*/
|
|
@@ -46,7 +47,7 @@ const create = root => ({
|
|
|
46
47
|
if ('overflow' in result) { return create(result.overflow) }
|
|
47
48
|
throw ''
|
|
48
49
|
},
|
|
49
|
-
entries: (
|
|
50
|
+
entries: valuesList(root),
|
|
50
51
|
root,
|
|
51
52
|
})
|
|
52
53
|
|
|
@@ -54,14 +55,14 @@ const create = root => ({
|
|
|
54
55
|
* @type {{
|
|
55
56
|
* readonly get: (name: string) => undefined
|
|
56
57
|
* readonly set: (name: string) => <T>(value: T) => Map<T>
|
|
57
|
-
* readonly entries: () =>
|
|
58
|
+
* readonly entries: () => undefined
|
|
58
59
|
* readonly root: undefined
|
|
59
60
|
* }}
|
|
60
61
|
*/
|
|
61
62
|
const empty = {
|
|
62
63
|
get: () => undefined,
|
|
63
64
|
set: name => value => create([[name, value]]),
|
|
64
|
-
entries:
|
|
65
|
+
entries: list.empty,
|
|
65
66
|
root: undefined
|
|
66
67
|
}
|
|
67
68
|
|
package/map/test.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const { empty } = require('.')
|
|
2
|
+
const list = require('../sequence/list')
|
|
2
3
|
|
|
3
4
|
{
|
|
4
5
|
let m = empty.set('a')(1)
|
|
@@ -44,7 +45,7 @@ const { empty } = require('.')
|
|
|
44
45
|
if (m.get('x') !== 12) { throw 'error' }
|
|
45
46
|
if (m.get('y') !== 44) { throw 'error' }
|
|
46
47
|
if (m.get('a') !== undefined) { throw 'error' }
|
|
47
|
-
const entries = Array.from(m.entries
|
|
48
|
+
const entries = Array.from(list.iterable(m.entries))
|
|
48
49
|
if (entries.length !== 2) { throw 'error' }
|
|
49
50
|
}
|
|
50
51
|
|
package/module-manager/index.js
CHANGED
|
@@ -39,8 +39,8 @@ const seq = require('../sequence')
|
|
|
39
39
|
|
|
40
40
|
/** @typedef {(_: string) => undefined|Package|Dependencies} Dependencies */
|
|
41
41
|
|
|
42
|
-
/** @type {seq.
|
|
43
|
-
const pathNormReduce = seq.
|
|
42
|
+
/** @type {seq.ExclusiveScan<string, undefined|Path>} */
|
|
43
|
+
const pathNormReduce = seq.exclusiveScan
|
|
44
44
|
(path => item =>
|
|
45
45
|
path === undefined ?
|
|
46
46
|
undefined :
|
package/package.json
CHANGED
package/sequence/README.md
CHANGED
|
@@ -12,7 +12,7 @@ Sequence types:
|
|
|
12
12
|
See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array
|
|
13
13
|
|
|
14
14
|
- `length: Sequence<infer T> => number`
|
|
15
|
-
- `at: number => Sequence<infer T> = T`
|
|
15
|
+
- `at: number => Sequence<infer T> = T|undefined`
|
|
16
16
|
- `concat: Sequence<infer T> => Sequence<T> => Sequence<T>`
|
|
17
17
|
- `entries: Sequence<infer T> => Sequence<[number, T]>`
|
|
18
18
|
- `every: (infer T => boolean) => Sequence<T> => boolean`
|
|
@@ -24,7 +24,6 @@ See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Obj
|
|
|
24
24
|
- `includes: infer T => Sequence<T> => boolean`
|
|
25
25
|
- `indexOf: infer T => Sequence<T> => number`
|
|
26
26
|
- `join: string => Sequence<string> => string`
|
|
27
|
-
- `keys: Sequence<T> => Sequence<string>`
|
|
28
27
|
- `lastIndexOf: infer T => Sequence<T> => number`
|
|
29
28
|
- `map: (infer T => infer R) => Sequence<T> => Sequence<R>`
|
|
30
29
|
- `reduce: ...Scan<T, R> => Sequence<T> => R`
|
|
@@ -38,6 +37,7 @@ See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Obj
|
|
|
38
37
|
|
|
39
38
|
### Priority 3.
|
|
40
39
|
|
|
40
|
+
- `keys: Sequence<T> => Sequence<string>`
|
|
41
41
|
- `values: Sequence<infer T> => Sequence<T>`
|
|
42
42
|
|
|
43
43
|
## Prohibited Array Operations
|
package/sequence/array/index.js
CHANGED
|
@@ -55,10 +55,10 @@ const scan = s => c => ({
|
|
|
55
55
|
}
|
|
56
56
|
})
|
|
57
57
|
|
|
58
|
-
/** @type {<T, R>(s: seq.
|
|
59
|
-
const
|
|
58
|
+
/** @type {<T, R>(s: seq.ExclusiveScan<T, R>) => (c: AsyncOrSyncIterable<T>) => AsyncIterable<R>} */
|
|
59
|
+
const exclusiveScan = ([first, s]) => c => concat([first])(scan(s)(c))
|
|
60
60
|
|
|
61
|
-
/** @type {<T, R>(is: seq.
|
|
61
|
+
/** @type {<T, R>(is: seq.ExclusiveScan<T, R>) => (c: AsyncOrSyncIterable<T>) => Promise<R>} */
|
|
62
62
|
const reduce = ([first, s]) => async c => {
|
|
63
63
|
let next = first
|
|
64
64
|
for await (const i of scan(s)(c)) {
|
|
@@ -105,7 +105,7 @@ module.exports = {
|
|
|
105
105
|
/** @readonly */
|
|
106
106
|
scan,
|
|
107
107
|
/** @readonly */
|
|
108
|
-
|
|
108
|
+
exclusiveScan,
|
|
109
109
|
/** @readonly */
|
|
110
110
|
takeWhile,
|
|
111
111
|
}
|
package/sequence/index.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
const op = require('../function/operator')
|
|
2
|
-
const { id } = require('../function')
|
|
3
2
|
|
|
4
3
|
/**
|
|
5
4
|
* @template T0
|
|
@@ -22,12 +21,12 @@ const { id } = require('../function')
|
|
|
22
21
|
/**
|
|
23
22
|
* @template T
|
|
24
23
|
* @template R
|
|
25
|
-
* @typedef {Tuple2<R, Scan<T, R>>}
|
|
24
|
+
* @typedef {Tuple2<R, Scan<T, R>>} ExclusiveScan
|
|
26
25
|
*/
|
|
27
26
|
|
|
28
|
-
/** @type {<R, T>(operator: op.
|
|
27
|
+
/** @type {<R, T>(operator: op.ReduceOperator<R, T>) => (prior: R) => Scan<T, R>} */
|
|
29
28
|
const scan = operator => {
|
|
30
|
-
/** @typedef {typeof operator extends op.
|
|
29
|
+
/** @typedef {typeof operator extends op.ReduceOperator<infer R, infer T> ? [R, T] : never} RT */
|
|
31
30
|
/** @typedef {RT[0]} R */
|
|
32
31
|
/** @typedef {RT[1]} T */
|
|
33
32
|
/** @type {(prior: R) => Scan<T, R>} */
|
|
@@ -38,8 +37,8 @@ const scan = operator => {
|
|
|
38
37
|
return f
|
|
39
38
|
}
|
|
40
39
|
|
|
41
|
-
/** @type {<R, T>(operator: op.
|
|
42
|
-
const
|
|
40
|
+
/** @type {<R, T>(operator: op.ReduceOperator<R, T>) => (first: R) => ExclusiveScan<T, R>} */
|
|
41
|
+
const exclusiveScan = operator => first => [first, scan(operator)(first)]
|
|
43
42
|
|
|
44
43
|
/**
|
|
45
44
|
* @template T
|
|
@@ -51,12 +50,15 @@ const createEntries = index => value => [[index, value], createEntries(index + 1
|
|
|
51
50
|
|
|
52
51
|
const entries = createEntries(0)
|
|
53
52
|
|
|
54
|
-
/** @type {(separator: string) =>
|
|
53
|
+
/** @type {(separator: string) => ExclusiveScan<string, string>} */
|
|
55
54
|
const join = separator => ['', value => [value, scan(op.join(separator))(value)]]
|
|
56
55
|
|
|
57
|
-
const sum =
|
|
56
|
+
const sum = exclusiveScan(op.addition)(0)
|
|
58
57
|
|
|
59
|
-
|
|
58
|
+
/** @type {(a: number) => () => number} */
|
|
59
|
+
const counter = a => () => a + 1
|
|
60
|
+
|
|
61
|
+
const length = exclusiveScan(counter)(0)
|
|
60
62
|
|
|
61
63
|
/**
|
|
62
64
|
* @template T
|
|
@@ -72,7 +74,7 @@ const filter = flatMap => f => flatMap(x => f(x) ? [x] : [])
|
|
|
72
74
|
|
|
73
75
|
module.exports = {
|
|
74
76
|
/** @readonly */
|
|
75
|
-
|
|
77
|
+
exclusiveScan,
|
|
76
78
|
/** @readonly */
|
|
77
79
|
scan,
|
|
78
80
|
/** @readonly */
|
|
@@ -21,10 +21,10 @@ const scan = s => c => ({
|
|
|
21
21
|
}
|
|
22
22
|
})
|
|
23
23
|
|
|
24
|
-
/** @type {<T, R>(s: seq.
|
|
25
|
-
const
|
|
24
|
+
/** @type {<T, R>(s: seq.ExclusiveScan<T, R>) => (c: Iterable<T>) => Iterable<R>} */
|
|
25
|
+
const exclusiveScan = ([first, s]) => c => concat([first])(scan(s)(c))
|
|
26
26
|
|
|
27
|
-
/** @type {<T, R>(s: seq.
|
|
27
|
+
/** @type {<T, R>(s: seq.ExclusiveScan<T, R>) => (c: Iterable<T>) => R} */
|
|
28
28
|
const reduce = ([first, s]) => c => {
|
|
29
29
|
let next = first
|
|
30
30
|
for (const i of scan(s)(c)) {
|
|
@@ -93,7 +93,7 @@ module.exports = {
|
|
|
93
93
|
/** @readonly */
|
|
94
94
|
scan,
|
|
95
95
|
/** @readonly */
|
|
96
|
-
|
|
96
|
+
exclusiveScan,
|
|
97
97
|
/** @readonly */
|
|
98
98
|
flatMap,
|
|
99
99
|
/** @readonly */
|
package/sequence/list/index.js
CHANGED
|
@@ -1,12 +1,28 @@
|
|
|
1
1
|
const array = require('../array')
|
|
2
|
-
const option = require('../../option')
|
|
3
2
|
const base = require('..')
|
|
4
3
|
const { pipe } = require('../../function')
|
|
5
|
-
const {
|
|
4
|
+
const { logicalNot, strictEqual } = require('../../function/operator')
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
7
|
* @template T
|
|
9
|
-
* @typedef {() => Result<T>}
|
|
8
|
+
* @typedef {() => Result<T>} ListFunc
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @template T
|
|
13
|
+
* @typedef {readonly [List<T>, List<T>]} Concat
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Use `next` function to get `first` and `tail` of the list.
|
|
18
|
+
*
|
|
19
|
+
* Please note that the list also contains `Concat<T>. We need this as
|
|
20
|
+
* a workaround because modern JavaScript implementations don't support
|
|
21
|
+
* ES6 TCO (Tail Call Optimization). Without this wotkaround we may have
|
|
22
|
+
* a stack overflow if a list contains a lot of concateneted lists.
|
|
23
|
+
*
|
|
24
|
+
* @template T
|
|
25
|
+
* @typedef { ListFunc<T> | Concat<T>} List
|
|
10
26
|
*/
|
|
11
27
|
|
|
12
28
|
/**
|
|
@@ -21,60 +37,72 @@ const { todo } = require('../../dev')
|
|
|
21
37
|
|
|
22
38
|
const empty = () => undefined
|
|
23
39
|
|
|
40
|
+
/** @type {<F, T>(a: readonly[F, List<T>]) => (b: List<T>) => readonly[F, List<T>]} */
|
|
41
|
+
const norm = ([a0, a1]) => b => [a0, [a1, b]]
|
|
42
|
+
|
|
43
|
+
/** @type {<T>(list: List<T>) => Result<T>} */
|
|
44
|
+
const next = list => {
|
|
45
|
+
let i = list
|
|
46
|
+
while (true) {
|
|
47
|
+
if (typeof i === 'function') { return i() }
|
|
48
|
+
const [a, b] = i
|
|
49
|
+
if (typeof a === 'function') {
|
|
50
|
+
const result = a()
|
|
51
|
+
if (result !== undefined) {
|
|
52
|
+
return norm(result)(b)
|
|
53
|
+
}
|
|
54
|
+
i = b
|
|
55
|
+
} else {
|
|
56
|
+
i = norm(a)(b)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** @type {<T>(list: List<T>) => T|undefined} */
|
|
62
|
+
const first = list => {
|
|
63
|
+
const result = next(list)
|
|
64
|
+
if (result === undefined) { return undefined }
|
|
65
|
+
return result[0]
|
|
66
|
+
}
|
|
67
|
+
|
|
24
68
|
/**
|
|
25
69
|
* @template T
|
|
26
70
|
* @template R
|
|
27
71
|
* @typedef {(list: List<T>) => List<R>} ListMap
|
|
28
72
|
*/
|
|
29
73
|
|
|
30
|
-
/**
|
|
31
|
-
|
|
74
|
+
/**
|
|
75
|
+
* @template T
|
|
76
|
+
* @template R
|
|
77
|
+
* @typedef {(list: List<T>) => R} ListReduce
|
|
78
|
+
*/
|
|
32
79
|
|
|
33
80
|
/** @type {<T>(first: T) => List<T>} */
|
|
34
|
-
const one = first =>
|
|
81
|
+
const one = first => () => [first, empty]
|
|
35
82
|
|
|
36
83
|
/** @type {<T>(array: array.Array<T>) => List<T>} */
|
|
37
84
|
const fromArray = a => {
|
|
38
85
|
/** @typedef {typeof a extends array.Array<infer T> ? T : never} T */
|
|
39
86
|
/** @type {(index: number) => List<T>} */
|
|
40
|
-
const at = index => {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
return
|
|
87
|
+
const at = index => () => {
|
|
88
|
+
const result = array.at(index)(a)
|
|
89
|
+
if (result === undefined) { return undefined }
|
|
90
|
+
return [result[0], at(index + 1)]
|
|
44
91
|
}
|
|
45
92
|
return at(0)
|
|
46
93
|
}
|
|
47
94
|
|
|
48
|
-
/**
|
|
49
|
-
|
|
50
|
-
* it calls `a()` as soon as `a` and `b` are provided.
|
|
51
|
-
* Othrewise we may have a stack overflow if a list
|
|
52
|
-
* contains a lot of concateneted empty lists.
|
|
53
|
-
* And we can't relay on ES6 TCO (Tail Call Optimization)
|
|
54
|
-
* because it's not supported by Chrome and Firefox.
|
|
55
|
-
* @type {<T>(list0: List<T>) => ListMap<T, T>}
|
|
56
|
-
*/
|
|
57
|
-
const concat = a => b => {
|
|
58
|
-
const result = a()
|
|
59
|
-
if (result !== undefined) {
|
|
60
|
-
const [first, tail] = result
|
|
61
|
-
return () => [first, concat(tail)(b)]
|
|
62
|
-
}
|
|
63
|
-
return b
|
|
64
|
-
// /** @typedef {typeof a extends List<infer T> ? T : never} T */
|
|
65
|
-
// /** @type {(firstAntTail: FirstAndTail<T>) => Result<T>} */
|
|
66
|
-
// const defined = ([first, tail]) => [first, concat(tail)(b)]
|
|
67
|
-
// return option.match(defined)(b)(a())
|
|
68
|
-
}
|
|
95
|
+
/** @type {<T>(list0: List<T>) => ListMap<T, T>} */
|
|
96
|
+
const concat = a => b => [a, b]
|
|
69
97
|
|
|
70
98
|
/** @type {<T, R>(f: (value: T) => List<R>) => ListMap<T, R>} */
|
|
71
99
|
const flatMap = f => input => () => {
|
|
72
100
|
let i = input
|
|
73
101
|
while (true) {
|
|
74
|
-
const result = i
|
|
102
|
+
const result = next(i)
|
|
75
103
|
if (result === undefined) { return undefined }
|
|
76
104
|
const [first, tail] = result
|
|
77
|
-
const firstResult = f(first)
|
|
105
|
+
const firstResult = next(f(first))
|
|
78
106
|
if (firstResult !== undefined) {
|
|
79
107
|
const [firstFirst, firstTail] = firstResult
|
|
80
108
|
return [firstFirst, concat(firstTail)(flatMap(f)(tail))]
|
|
@@ -92,35 +120,46 @@ const map = f => flatMap(i => one(f(i)))
|
|
|
92
120
|
/** @type {<T>(f: (value: T) => boolean) => ListMap<T, T>} */
|
|
93
121
|
const filter = f => flatMap(i => f(i) ? one(i) : empty)
|
|
94
122
|
|
|
123
|
+
/** @type {<T, R>(f: (value: T) => R|undefined) => (value: T) => List<R>} */
|
|
124
|
+
const filterMapFunc = f => i => {
|
|
125
|
+
const result = f(i)
|
|
126
|
+
if (result === undefined) { return empty }
|
|
127
|
+
return one(result)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/** @type {<T, R>(f: (value: T) => R|undefined) => ListMap<T, R>} */
|
|
131
|
+
const filterMap = f => flatMap(filterMapFunc(f))
|
|
132
|
+
|
|
95
133
|
/** @type {<T, R>(s: base.Scan<T, R>) => ListMap<T, R>} */
|
|
96
134
|
const scan = s => input => () => {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
/** @type {(firstAndTail: FirstAndTail<T>) => Result<R>} */
|
|
101
|
-
const defined = ([first, tail]) => {
|
|
102
|
-
const [newFirst, newS] = s(first)
|
|
103
|
-
return [newFirst, scan(newS)(tail)]
|
|
135
|
+
const result = next(input)
|
|
136
|
+
if (result === undefined) {
|
|
137
|
+
return result
|
|
104
138
|
}
|
|
105
|
-
|
|
139
|
+
const [first, tail] = result
|
|
140
|
+
const [newFirst, newS] = s(first)
|
|
141
|
+
return [newFirst, scan(newS)(tail)]
|
|
106
142
|
}
|
|
107
143
|
|
|
108
|
-
/** @type {<T, R>(s: base.
|
|
109
|
-
const
|
|
144
|
+
/** @type {<T, R>(s: base.ExclusiveScan<T, R>) => ListMap<T, R>} */
|
|
145
|
+
const exclusiveScan = ([first, s]) => input => () => [first, scan(s)(input)]
|
|
110
146
|
|
|
111
147
|
/** @type {<T>(def: T) => (input: List<T>) => T} */
|
|
112
148
|
const last = def => input => {
|
|
113
|
-
let i = input()
|
|
114
149
|
let r = def
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
150
|
+
let i = input
|
|
151
|
+
while (true) {
|
|
152
|
+
const result = next(i)
|
|
153
|
+
if (result === undefined) {
|
|
154
|
+
return r
|
|
155
|
+
}
|
|
156
|
+
r = result[0]
|
|
157
|
+
i = result[1]
|
|
118
158
|
}
|
|
119
|
-
return r
|
|
120
159
|
}
|
|
121
160
|
|
|
122
|
-
/** @type {<T, R>(s: base.
|
|
123
|
-
const reduce = s => input => last(
|
|
161
|
+
/** @type {<T, R>(s: base.ExclusiveScan<T, R>) => (input: List<T>) => R} */
|
|
162
|
+
const reduce = ([first, s]) => input => last(first)(scan(s)(input))
|
|
124
163
|
|
|
125
164
|
const entries = scan(base.entries)
|
|
126
165
|
|
|
@@ -130,42 +169,100 @@ const length = reduce(base.length)
|
|
|
130
169
|
|
|
131
170
|
const join = pipe(base.join)(reduce)
|
|
132
171
|
|
|
133
|
-
/** @type {<T>(f: (value: T) => boolean) =>
|
|
134
|
-
const
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
return option.map(defined)(filter(f)(input)())
|
|
172
|
+
/** @type {<T>(f: (value: T) => boolean) => ListMap<T, T>} */
|
|
173
|
+
const takeWhile = f => input => () => {
|
|
174
|
+
const result = next(input)
|
|
175
|
+
if (result === undefined || !f(result[0])) { return undefined }
|
|
176
|
+
return result
|
|
139
177
|
}
|
|
140
178
|
|
|
141
|
-
/**
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
179
|
+
/** @type {(n: number) => <T>(input: List<T>) => List<T>} */
|
|
180
|
+
const drop = n => input => () => {
|
|
181
|
+
let iN = n
|
|
182
|
+
let iInput = input
|
|
183
|
+
while (true) {
|
|
184
|
+
const result = next(iInput)
|
|
185
|
+
if (iN <= 0 || result === undefined) { return result }
|
|
186
|
+
iN = iN - 1
|
|
187
|
+
iInput = result[1]
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/** @type {(n: number) => <T>(input: List<T>) => T|undefined} */
|
|
192
|
+
const at = n => input => first(drop(n)(input))
|
|
193
|
+
|
|
194
|
+
/** @type {<T>(f: (value: T) => boolean) => ListReduce<T, T|undefined>} */
|
|
195
|
+
const find = f => input => first(filter(f)(input))
|
|
196
|
+
|
|
197
|
+
/** @type {<T>(f: (value: T) => boolean) => ListReduce<T, boolean>} */
|
|
198
|
+
const some = f => input => find(x => x)(map(f)(input)) !== undefined
|
|
199
|
+
|
|
200
|
+
/** @type {<T>(value: T) => ListReduce<T, boolean>} */
|
|
201
|
+
const includes = value => some(strictEqual(value))
|
|
202
|
+
|
|
203
|
+
/** @type {<T>(f: (value: T) => boolean) => ListReduce<T, boolean>} */
|
|
204
|
+
const every = f => input => !some(pipe(f)(logicalNot))(input)
|
|
205
|
+
|
|
206
|
+
/** @type {<T>(list: List<T>) => Iterable<T>} */
|
|
145
207
|
const iterable = list => ({
|
|
146
208
|
*[Symbol.iterator]() {
|
|
147
|
-
let
|
|
148
|
-
while (
|
|
209
|
+
let i = list
|
|
210
|
+
while (true) {
|
|
211
|
+
const result = next(i)
|
|
212
|
+
if (result === undefined) { return }
|
|
213
|
+
yield result[0]
|
|
214
|
+
i = result[1]
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
/** @type {<T>(list: List<T>) => AsyncIterable<T>} */
|
|
220
|
+
const asyncIterable = list => ({
|
|
221
|
+
async *[Symbol.asyncIterator]() {
|
|
222
|
+
let i = list
|
|
223
|
+
while (true) {
|
|
224
|
+
const result = next(i)
|
|
225
|
+
if (result === undefined) { return }
|
|
149
226
|
yield result[0]
|
|
150
|
-
|
|
227
|
+
i = result[1]
|
|
151
228
|
}
|
|
152
229
|
}
|
|
153
230
|
})
|
|
154
231
|
|
|
232
|
+
/** @type {<A>(a: List<A>) => <B>(b: List<B>) => List<array.Tuple2<A, B>>} */
|
|
233
|
+
const zip = a => b => () => {
|
|
234
|
+
const resultA = next(a)
|
|
235
|
+
if (resultA === undefined) { return undefined }
|
|
236
|
+
const resultB = next(b)
|
|
237
|
+
if (resultB === undefined) { return undefined }
|
|
238
|
+
return [[resultA[0], resultB[0]], zip(resultA[1])(resultB[1])]
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/** @type {<T>(list: List<T>) => readonly T[]} */
|
|
242
|
+
const toArray = input => Array.from(iterable(input))
|
|
243
|
+
|
|
155
244
|
module.exports = {
|
|
156
245
|
/** @readonly */
|
|
157
|
-
|
|
246
|
+
next,
|
|
158
247
|
/** @readonly */
|
|
159
248
|
one,
|
|
160
249
|
/** @readonly */
|
|
161
250
|
empty,
|
|
162
251
|
/** @readonly */
|
|
252
|
+
at,
|
|
253
|
+
/** @readonly */
|
|
163
254
|
concat,
|
|
164
255
|
/** @readonly */
|
|
256
|
+
first,
|
|
257
|
+
/** @readonly */
|
|
165
258
|
fromArray,
|
|
166
259
|
/** @readonly */
|
|
260
|
+
toArray,
|
|
261
|
+
/** @readonly */
|
|
167
262
|
iterable,
|
|
168
263
|
/** @readonly */
|
|
264
|
+
asyncIterable,
|
|
265
|
+
/** @readonly */
|
|
169
266
|
flatMap,
|
|
170
267
|
/** @readonly */
|
|
171
268
|
flat,
|
|
@@ -174,9 +271,11 @@ module.exports = {
|
|
|
174
271
|
/** @readonly */
|
|
175
272
|
filter,
|
|
176
273
|
/** @readonly */
|
|
274
|
+
filterMap,
|
|
275
|
+
/** @readonly */
|
|
177
276
|
scan,
|
|
178
277
|
/** @readonly */
|
|
179
|
-
|
|
278
|
+
exclusiveScan,
|
|
180
279
|
/** @readonly */
|
|
181
280
|
last,
|
|
182
281
|
/** @readonly */
|
|
@@ -190,5 +289,17 @@ module.exports = {
|
|
|
190
289
|
/** @readonly */
|
|
191
290
|
length,
|
|
192
291
|
/** @readonly */
|
|
292
|
+
drop,
|
|
293
|
+
/** @readonly */
|
|
193
294
|
find,
|
|
295
|
+
/** @readonly */
|
|
296
|
+
takeWhile,
|
|
297
|
+
/** @readonly */
|
|
298
|
+
some,
|
|
299
|
+
/** @readonly */
|
|
300
|
+
every,
|
|
301
|
+
/** @readonly */
|
|
302
|
+
includes,
|
|
303
|
+
/** @readonly */
|
|
304
|
+
zip,
|
|
194
305
|
}
|
package/sequence/list/test.js
CHANGED
|
@@ -3,10 +3,12 @@ const { sum } = require('..')
|
|
|
3
3
|
|
|
4
4
|
/** @type {<T>(l: list.List<T>) => void} */
|
|
5
5
|
const print = a => {
|
|
6
|
-
let i = a
|
|
7
|
-
while (
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
let i = a
|
|
7
|
+
while (true) {
|
|
8
|
+
const result = list.next(i)
|
|
9
|
+
if (result === undefined) { return }
|
|
10
|
+
// console.log(result[0])
|
|
11
|
+
i = result[1]
|
|
10
12
|
}
|
|
11
13
|
}
|
|
12
14
|
|
|
@@ -15,22 +17,27 @@ const print = a => {
|
|
|
15
17
|
const list0 = list.fromArray([0, 1, 2, 3])
|
|
16
18
|
const list1 = list.flatMap(x => list.fromArray([x, x * 2, x * 3]))(list0)
|
|
17
19
|
const list2 = list.concat(list0)(list0)
|
|
18
|
-
const list3 = list.
|
|
20
|
+
const list3 = list.exclusiveScan(sum)(list0)
|
|
19
21
|
const r = list.find(x => x === 42)(big)
|
|
22
|
+
if (list.every(x => x > 0)(big) !== true) { throw 'x'}
|
|
23
|
+
if (list.every(x => x < 20)(big) !== false) { throw 'x' }
|
|
24
|
+
if (list.some(x => x > 100)(big) !== false) { throw 'x' }
|
|
25
|
+
if (list.some(x => x > 50)(big) !== true) { throw 'x' }
|
|
26
|
+
if (list.first(list.drop(16)(big)) !== 42) { throw 'drop'}
|
|
20
27
|
{
|
|
21
28
|
let x = big
|
|
22
|
-
for (let i = 0; i <
|
|
29
|
+
for (let i = 0; i < 1_000_000; ++i) {
|
|
23
30
|
x = list.concat(list.empty)(x)
|
|
24
31
|
}
|
|
25
|
-
const r = x
|
|
26
|
-
print(x)
|
|
32
|
+
const r = list.next(x)
|
|
33
|
+
// print(x)
|
|
27
34
|
}
|
|
28
35
|
{
|
|
29
36
|
let x = big
|
|
30
|
-
for (let i = 0; i <
|
|
31
|
-
x = list.concat(x)(list.
|
|
37
|
+
for (let i = 0; i < 1_000_000; ++i) {
|
|
38
|
+
x = list.concat(x)(list.one(i))
|
|
32
39
|
}
|
|
33
|
-
const r = x
|
|
34
|
-
print(x)
|
|
40
|
+
const r = list.next(x)
|
|
41
|
+
// print(x)
|
|
35
42
|
}
|
|
36
43
|
}
|