functionalscript 0.0.174 → 0.0.181
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/btree/index.js +1 -1
- package/btree/test.js +3 -2
- package/package.json +1 -1
- package/sequence/README.md +2 -2
- package/sequence/array/index.js +7 -0
- package/sequence/index.js +4 -1
- package/sequence/list/index.js +83 -36
- package/sequence/list/test.js +23 -9
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.get(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.get(result[1])
|
|
29
30
|
}
|
|
30
31
|
}
|
|
31
32
|
}
|
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
package/sequence/index.js
CHANGED
|
@@ -56,7 +56,10 @@ const join = separator => ['', value => [value, scan(op.join(separator))(value)]
|
|
|
56
56
|
|
|
57
57
|
const sum = inclusiveScan(op.addition)(0)
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
/** @type {(a: number) => () => number} */
|
|
60
|
+
const counter = a => () => a + 1
|
|
61
|
+
|
|
62
|
+
const length = inclusiveScan(counter)(0)
|
|
60
63
|
|
|
61
64
|
/**
|
|
62
65
|
* @template T
|
package/sequence/list/index.js
CHANGED
|
@@ -2,10 +2,27 @@ const array = require('../array')
|
|
|
2
2
|
const option = require('../../option')
|
|
3
3
|
const base = require('..')
|
|
4
4
|
const { pipe } = require('../../function')
|
|
5
|
+
const { todo } = require('../../dev')
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* @template T
|
|
8
|
-
* @typedef {() => Result<T>}
|
|
9
|
+
* @typedef {() => Result<T>} ListFunc
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* We need this workaround because modern JavaScript implementations
|
|
14
|
+
* don't support ES6 TCO (Tail Call Optimization)
|
|
15
|
+
*
|
|
16
|
+
* Without this wotkaround we may have a stack overflow if a list
|
|
17
|
+
* contains a lot of concateneted lists.
|
|
18
|
+
*
|
|
19
|
+
* @template T
|
|
20
|
+
* @typedef {readonly [List<T>, List<T>]} Concat
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @template T
|
|
25
|
+
* @typedef { ListFunc<T> | Concat<T>} List
|
|
9
26
|
*/
|
|
10
27
|
|
|
11
28
|
/**
|
|
@@ -20,48 +37,65 @@ const { pipe } = require('../../function')
|
|
|
20
37
|
|
|
21
38
|
const empty = () => undefined
|
|
22
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 get = 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
|
+
|
|
23
61
|
/**
|
|
24
62
|
* @template T
|
|
25
63
|
* @template R
|
|
26
64
|
* @typedef {(list: List<T>) => List<R>} ListMap
|
|
27
65
|
*/
|
|
28
66
|
|
|
29
|
-
/** @type {<T>(first: T) => ListMap<T, T>} */
|
|
30
|
-
const list = first => tail => () => [first, tail]
|
|
31
|
-
|
|
32
67
|
/** @type {<T>(first: T) => List<T>} */
|
|
33
|
-
const one = first =>
|
|
68
|
+
const one = first => () => [first, empty]
|
|
34
69
|
|
|
35
70
|
/** @type {<T>(array: array.Array<T>) => List<T>} */
|
|
36
71
|
const fromArray = a => {
|
|
37
72
|
/** @typedef {typeof a extends array.Array<infer T> ? T : never} T */
|
|
38
73
|
/** @type {(index: number) => List<T>} */
|
|
39
|
-
const at = index => {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
return
|
|
74
|
+
const at = index => () => {
|
|
75
|
+
const result = array.at(index)(a)
|
|
76
|
+
if (result === undefined) { return undefined }
|
|
77
|
+
return [result[0], at(index + 1)]
|
|
43
78
|
}
|
|
44
79
|
return at(0)
|
|
45
80
|
}
|
|
46
81
|
|
|
47
82
|
/** @type {<T>(list0: List<T>) => ListMap<T, T>} */
|
|
48
|
-
const concat = a => b =>
|
|
49
|
-
/** @typedef {typeof a extends List<infer T> ? T : never} T */
|
|
50
|
-
/** @type {(firstAntTail: FirstAndTail<T>) => Result<T>} */
|
|
51
|
-
const defined = ([first, tail]) => [first, concat(tail)(b)]
|
|
52
|
-
return option.match(defined)(b)(a())
|
|
53
|
-
}
|
|
83
|
+
const concat = a => b => [a, b]
|
|
54
84
|
|
|
55
85
|
/** @type {<T, R>(f: (value: T) => List<R>) => ListMap<T, R>} */
|
|
56
|
-
const flatMap = f => {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
86
|
+
const flatMap = f => input => () => {
|
|
87
|
+
let i = input
|
|
88
|
+
while (true) {
|
|
89
|
+
const result = get(i)
|
|
90
|
+
if (result === undefined) { return undefined }
|
|
91
|
+
const [first, tail] = result
|
|
92
|
+
const firstResult = get(f(first))
|
|
93
|
+
if (firstResult !== undefined) {
|
|
94
|
+
const [firstFirst, firstTail] = firstResult
|
|
95
|
+
return [firstFirst, concat(firstTail)(flatMap(f)(tail))]
|
|
96
|
+
}
|
|
97
|
+
i = tail
|
|
98
|
+
}
|
|
65
99
|
}
|
|
66
100
|
|
|
67
101
|
/** @type {<T>(list: List<List<T>>) => List<T>} */
|
|
@@ -83,25 +117,29 @@ const scan = s => input => () => {
|
|
|
83
117
|
const [newFirst, newS] = s(first)
|
|
84
118
|
return [newFirst, scan(newS)(tail)]
|
|
85
119
|
}
|
|
86
|
-
return option.map(defined)(input
|
|
120
|
+
return option.map(defined)(get(input))
|
|
87
121
|
}
|
|
88
122
|
|
|
89
123
|
/** @type {<T, R>(s: base.InclusiveScan<T, R>) => ListMap<T, R>} */
|
|
90
|
-
const inclusiveScan = ([first, s]) => input =>
|
|
124
|
+
const inclusiveScan = ([first, s]) => input => () => [first, scan(s)(input)]
|
|
91
125
|
|
|
92
126
|
/** @type {<T>(def: T) => (input: List<T>) => T} */
|
|
93
127
|
const last = def => input => {
|
|
94
|
-
let i = input()
|
|
95
128
|
let r = def
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
129
|
+
let i = input
|
|
130
|
+
while (true) {
|
|
131
|
+
const result = get(i)
|
|
132
|
+
if (result === undefined) {
|
|
133
|
+
return r
|
|
134
|
+
}
|
|
135
|
+
r = result[0]
|
|
136
|
+
i = result[1]
|
|
99
137
|
}
|
|
100
138
|
return r
|
|
101
139
|
}
|
|
102
140
|
|
|
103
141
|
/** @type {<T, R>(s: base.InclusiveScan<T, R>) => (input: List<T>) => R} */
|
|
104
|
-
const reduce = s => input => last(
|
|
142
|
+
const reduce = ([first, s]) => input => last(first)(scan(s)(input))
|
|
105
143
|
|
|
106
144
|
const entries = scan(base.entries)
|
|
107
145
|
|
|
@@ -111,12 +149,19 @@ const length = reduce(base.length)
|
|
|
111
149
|
|
|
112
150
|
const join = pipe(base.join)(reduce)
|
|
113
151
|
|
|
152
|
+
/** @type {<T>(f: (value: T) => boolean) => ListMap<T, T>} */
|
|
153
|
+
const takeWhile = f => input => () => {
|
|
154
|
+
const result = get(input)
|
|
155
|
+
if (result === undefined || !f(result[0])) { return undefined }
|
|
156
|
+
return result
|
|
157
|
+
}
|
|
158
|
+
|
|
114
159
|
/** @type {<T>(f: (value: T) => boolean) => (input: List<T>) => T|undefined} */
|
|
115
160
|
const find = f => input => {
|
|
116
161
|
/** @typedef {typeof f extends (value: infer T) => boolean ? T : never} T */
|
|
117
162
|
/** @type {(result: FirstAndTail<T>) => T} */
|
|
118
163
|
const defined = ([first]) => first
|
|
119
|
-
return option.map(defined)(filter(f)(input)
|
|
164
|
+
return option.map(defined)(get(filter(f)(input)))
|
|
120
165
|
}
|
|
121
166
|
|
|
122
167
|
/**
|
|
@@ -125,17 +170,19 @@ const find = f => input => {
|
|
|
125
170
|
*/
|
|
126
171
|
const iterable = list => ({
|
|
127
172
|
*[Symbol.iterator]() {
|
|
128
|
-
let
|
|
129
|
-
while (
|
|
173
|
+
let i = list
|
|
174
|
+
while (true) {
|
|
175
|
+
const result = get(i)
|
|
176
|
+
if (result === undefined) { return }
|
|
130
177
|
yield result[0]
|
|
131
|
-
|
|
178
|
+
i = result[1]
|
|
132
179
|
}
|
|
133
180
|
}
|
|
134
181
|
})
|
|
135
182
|
|
|
136
183
|
module.exports = {
|
|
137
184
|
/** @readonly */
|
|
138
|
-
|
|
185
|
+
get,
|
|
139
186
|
/** @readonly */
|
|
140
187
|
one,
|
|
141
188
|
/** @readonly */
|
package/sequence/list/test.js
CHANGED
|
@@ -3,22 +3,36 @@ 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.get(i)
|
|
9
|
+
if (result === undefined) { return }
|
|
10
|
+
console.log(result[0])
|
|
11
|
+
i = result[1]
|
|
10
12
|
}
|
|
11
13
|
}
|
|
12
14
|
|
|
13
15
|
{
|
|
14
16
|
const big = list.fromArray([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 42, 60])
|
|
15
|
-
print(big)
|
|
16
|
-
/*
|
|
17
17
|
const list0 = list.fromArray([0, 1, 2, 3])
|
|
18
18
|
const list1 = list.flatMap(x => list.fromArray([x, x * 2, x * 3]))(list0)
|
|
19
19
|
const list2 = list.concat(list0)(list0)
|
|
20
20
|
const list3 = list.inclusiveScan(sum)(list0)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
const r = list.find(x => x === 42)(big)
|
|
22
|
+
{
|
|
23
|
+
let x = big
|
|
24
|
+
for (let i = 0; i < 1_000_000; ++i) {
|
|
25
|
+
x = list.concat(list.empty)(x)
|
|
26
|
+
}
|
|
27
|
+
const r = list.get(x)
|
|
28
|
+
print(x)
|
|
29
|
+
}
|
|
30
|
+
{
|
|
31
|
+
let x = big
|
|
32
|
+
for (let i = 0; i < 1_000_000; ++i) {
|
|
33
|
+
x = list.concat(x)(list.one(i))
|
|
34
|
+
}
|
|
35
|
+
const r = list.get(x)
|
|
36
|
+
// print(x)
|
|
37
|
+
}
|
|
24
38
|
}
|