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