functionalscript 0.0.178 → 0.0.180
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 +69 -44
- package/sequence/list/test.js +12 -10
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
|
@@ -6,7 +6,23 @@ const { todo } = require('../../dev')
|
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* @template T
|
|
9
|
-
* @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
|
|
10
26
|
*/
|
|
11
27
|
|
|
12
28
|
/**
|
|
@@ -21,60 +37,56 @@ const { todo } = require('../../dev')
|
|
|
21
37
|
|
|
22
38
|
const empty = () => undefined
|
|
23
39
|
|
|
40
|
+
/** @type {<T>(list: List<T>) => Result<T>} */
|
|
41
|
+
const get = list => {
|
|
42
|
+
let i = list
|
|
43
|
+
while (true) {
|
|
44
|
+
if (typeof i === 'function') { return i() }
|
|
45
|
+
const [a, b] = i
|
|
46
|
+
if (typeof a === 'function') {
|
|
47
|
+
const result = a()
|
|
48
|
+
if (result !== undefined) {
|
|
49
|
+
return [result[0], [result[1], b]]
|
|
50
|
+
}
|
|
51
|
+
i = b
|
|
52
|
+
} else {
|
|
53
|
+
i = [a[0], [a[1], b]]
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
24
58
|
/**
|
|
25
59
|
* @template T
|
|
26
60
|
* @template R
|
|
27
61
|
* @typedef {(list: List<T>) => List<R>} ListMap
|
|
28
62
|
*/
|
|
29
63
|
|
|
30
|
-
/** @type {<T>(first: T) => ListMap<T, T>} */
|
|
31
|
-
const list = first => tail => () => [first, tail]
|
|
32
|
-
|
|
33
64
|
/** @type {<T>(first: T) => List<T>} */
|
|
34
|
-
const one = first =>
|
|
65
|
+
const one = first => () => [first, empty]
|
|
35
66
|
|
|
36
67
|
/** @type {<T>(array: array.Array<T>) => List<T>} */
|
|
37
68
|
const fromArray = a => {
|
|
38
69
|
/** @typedef {typeof a extends array.Array<infer T> ? T : never} T */
|
|
39
70
|
/** @type {(index: number) => List<T>} */
|
|
40
|
-
const at = index => {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
return
|
|
71
|
+
const at = index => () => {
|
|
72
|
+
const result = array.at(index)(a)
|
|
73
|
+
if (result === undefined) { return undefined }
|
|
74
|
+
return [result[0], at(index + 1)]
|
|
44
75
|
}
|
|
45
76
|
return at(0)
|
|
46
77
|
}
|
|
47
78
|
|
|
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
|
-
}
|
|
79
|
+
/** @type {<T>(list0: List<T>) => ListMap<T, T>} */
|
|
80
|
+
const concat = a => b => [a, b]
|
|
69
81
|
|
|
70
82
|
/** @type {<T, R>(f: (value: T) => List<R>) => ListMap<T, R>} */
|
|
71
83
|
const flatMap = f => input => () => {
|
|
72
84
|
let i = input
|
|
73
85
|
while (true) {
|
|
74
|
-
const result = i
|
|
86
|
+
const result = get(i)
|
|
75
87
|
if (result === undefined) { return undefined }
|
|
76
88
|
const [first, tail] = result
|
|
77
|
-
const firstResult = f(first)
|
|
89
|
+
const firstResult = get(f(first))
|
|
78
90
|
if (firstResult !== undefined) {
|
|
79
91
|
const [firstFirst, firstTail] = firstResult
|
|
80
92
|
return [firstFirst, concat(firstTail)(flatMap(f)(tail))]
|
|
@@ -102,25 +114,29 @@ const scan = s => input => () => {
|
|
|
102
114
|
const [newFirst, newS] = s(first)
|
|
103
115
|
return [newFirst, scan(newS)(tail)]
|
|
104
116
|
}
|
|
105
|
-
return option.map(defined)(input
|
|
117
|
+
return option.map(defined)(get(input))
|
|
106
118
|
}
|
|
107
119
|
|
|
108
120
|
/** @type {<T, R>(s: base.InclusiveScan<T, R>) => ListMap<T, R>} */
|
|
109
|
-
const inclusiveScan = ([first, s]) => input =>
|
|
121
|
+
const inclusiveScan = ([first, s]) => input => () => [first, scan(s)(input)]
|
|
110
122
|
|
|
111
123
|
/** @type {<T>(def: T) => (input: List<T>) => T} */
|
|
112
124
|
const last = def => input => {
|
|
113
|
-
let i = input()
|
|
114
125
|
let r = def
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
126
|
+
let i = input
|
|
127
|
+
while (true) {
|
|
128
|
+
const result = get(i)
|
|
129
|
+
if (result === undefined) {
|
|
130
|
+
return r
|
|
131
|
+
}
|
|
132
|
+
r = result[0]
|
|
133
|
+
i = result[1]
|
|
118
134
|
}
|
|
119
135
|
return r
|
|
120
136
|
}
|
|
121
137
|
|
|
122
138
|
/** @type {<T, R>(s: base.InclusiveScan<T, R>) => (input: List<T>) => R} */
|
|
123
|
-
const reduce = s => input => last(
|
|
139
|
+
const reduce = ([first, s]) => input => last(first)(scan(s)(input))
|
|
124
140
|
|
|
125
141
|
const entries = scan(base.entries)
|
|
126
142
|
|
|
@@ -130,12 +146,19 @@ const length = reduce(base.length)
|
|
|
130
146
|
|
|
131
147
|
const join = pipe(base.join)(reduce)
|
|
132
148
|
|
|
149
|
+
/** @type {<T>(f: (value: T) => boolean) => ListMap<T, T>} */
|
|
150
|
+
const takeWhile = f => input => () => {
|
|
151
|
+
const result = get(input)
|
|
152
|
+
if (result === undefined || !f(result[0])) { return undefined }
|
|
153
|
+
return result
|
|
154
|
+
}
|
|
155
|
+
|
|
133
156
|
/** @type {<T>(f: (value: T) => boolean) => (input: List<T>) => T|undefined} */
|
|
134
157
|
const find = f => input => {
|
|
135
158
|
/** @typedef {typeof f extends (value: infer T) => boolean ? T : never} T */
|
|
136
159
|
/** @type {(result: FirstAndTail<T>) => T} */
|
|
137
160
|
const defined = ([first]) => first
|
|
138
|
-
return option.map(defined)(filter(f)(input)
|
|
161
|
+
return option.map(defined)(get(filter(f)(input)))
|
|
139
162
|
}
|
|
140
163
|
|
|
141
164
|
/**
|
|
@@ -144,17 +167,19 @@ const find = f => input => {
|
|
|
144
167
|
*/
|
|
145
168
|
const iterable = list => ({
|
|
146
169
|
*[Symbol.iterator]() {
|
|
147
|
-
let
|
|
148
|
-
while (
|
|
170
|
+
let i = list
|
|
171
|
+
while (true) {
|
|
172
|
+
const result = get(i)
|
|
173
|
+
if (result === undefined) { return }
|
|
149
174
|
yield result[0]
|
|
150
|
-
|
|
175
|
+
i = result[1]
|
|
151
176
|
}
|
|
152
177
|
}
|
|
153
178
|
})
|
|
154
179
|
|
|
155
180
|
module.exports = {
|
|
156
181
|
/** @readonly */
|
|
157
|
-
|
|
182
|
+
get,
|
|
158
183
|
/** @readonly */
|
|
159
184
|
one,
|
|
160
185
|
/** @readonly */
|
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.get(i)
|
|
9
|
+
if (result === undefined) { return }
|
|
10
|
+
console.log(result[0])
|
|
11
|
+
i = result[1]
|
|
10
12
|
}
|
|
11
13
|
}
|
|
12
14
|
|
|
@@ -19,18 +21,18 @@ const print = a => {
|
|
|
19
21
|
const r = list.find(x => x === 42)(big)
|
|
20
22
|
{
|
|
21
23
|
let x = big
|
|
22
|
-
for (let i = 0; i <
|
|
24
|
+
for (let i = 0; i < 1_000_000; ++i) {
|
|
23
25
|
x = list.concat(list.empty)(x)
|
|
24
26
|
}
|
|
25
|
-
const r = x
|
|
27
|
+
const r = list.get(x)
|
|
26
28
|
print(x)
|
|
27
29
|
}
|
|
28
30
|
{
|
|
29
31
|
let x = big
|
|
30
|
-
for (let i = 0; i <
|
|
31
|
-
x = list.concat(x)(list.
|
|
32
|
+
for (let i = 0; i < 1_000_000; ++i) {
|
|
33
|
+
x = list.concat(x)(list.one(i))
|
|
32
34
|
}
|
|
33
|
-
const r = x
|
|
34
|
-
print(x)
|
|
35
|
+
const r = list.get(x)
|
|
36
|
+
// print(x)
|
|
35
37
|
}
|
|
36
38
|
}
|