functionalscript 0.0.217 → 0.0.222
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 +6 -0
- package/btree/index.js +4 -4
- package/btree/test.js +1 -1
- package/function/index.js +6 -2
- package/json/index.js +25 -25
- package/json/test.js +2 -1
- package/map/index.js +5 -3
- package/module-manager/index.js +2 -6
- package/object/index.js +0 -5
- package/package.json +2 -2
- package/sequence/README.md +16 -1
- package/sequence/array/index.js +0 -19
- package/sequence/asyncIterable/index.js +1 -1
- package/sequence/index.js +213 -234
- package/sequence/iterable/index.js +1 -1
- package/sequence/iterable/test.js +2 -2
- package/sequence/operator/index.js +1 -1
- package/sequence/test.js +124 -57
- package/test.js +3 -3
- package/sequence/operator/README.md +0 -41
package/README.md
CHANGED
|
@@ -13,6 +13,12 @@ Create a new FunctionalScript repository on GitHub [here](https://github.com/fun
|
|
|
13
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
14
|
A workaround for this problem is to use `let` for renaming objects.
|
|
15
15
|
|
|
16
|
+
## Install FunctionalScript As A Library
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
npm install -S github:functionalscript/functionalscript
|
|
20
|
+
```
|
|
21
|
+
|
|
16
22
|
## JSON
|
|
17
23
|
|
|
18
24
|
```js
|
package/btree/index.js
CHANGED
|
@@ -309,20 +309,20 @@ const replaceVisitor = {
|
|
|
309
309
|
const values = node => () => {
|
|
310
310
|
const f = () => {
|
|
311
311
|
switch (node.length) {
|
|
312
|
-
case 1: case 2: { return
|
|
312
|
+
case 1: case 2: { return node }
|
|
313
313
|
case 3: {
|
|
314
314
|
return seq.concat(
|
|
315
315
|
values(node[0]),
|
|
316
|
-
|
|
316
|
+
[node[1]],
|
|
317
317
|
values(node[2])
|
|
318
318
|
)
|
|
319
319
|
}
|
|
320
320
|
default: {
|
|
321
321
|
return seq.concat(
|
|
322
322
|
values(node[0]),
|
|
323
|
-
|
|
323
|
+
[node[1]],
|
|
324
324
|
values(node[2]),
|
|
325
|
-
|
|
325
|
+
[node[3]],
|
|
326
326
|
values(node[4])
|
|
327
327
|
)
|
|
328
328
|
}
|
package/btree/test.js
CHANGED
package/function/index.js
CHANGED
|
@@ -4,8 +4,12 @@
|
|
|
4
4
|
* @typedef {(_: I) => O} Func
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
/**
|
|
8
|
-
|
|
7
|
+
/**
|
|
8
|
+
* Postfix Compose function.
|
|
9
|
+
*
|
|
10
|
+
* @type {<I, X>(g: Func<I, X>) => <O>(f: Func<X, O>) => Func<I, O>}
|
|
11
|
+
*/
|
|
12
|
+
const compose = g => f => x => f(g(x))
|
|
9
13
|
|
|
10
14
|
/** @type {<T>(value: T) => T} */
|
|
11
15
|
const identity = value => value
|
package/json/index.js
CHANGED
|
@@ -14,53 +14,50 @@ const { compose } = require('../function')
|
|
|
14
14
|
|
|
15
15
|
/** @typedef {Object|boolean|string|number|null|Array} Json */
|
|
16
16
|
|
|
17
|
-
/** @type {(value: Json) => (path:
|
|
17
|
+
/** @type {(value: Json) => (path: seq.Sequence<string>) => (src: Json|undefined) => Json} */
|
|
18
18
|
const addProperty = value => {
|
|
19
19
|
/** @type {(path: seq.Sequence<string>) => (src: Json|undefined) => Json} */
|
|
20
20
|
const f = path => src => {
|
|
21
21
|
const result = seq.next(path)
|
|
22
22
|
if (result === undefined) { return value }
|
|
23
23
|
const srcObject = (src === undefined || src === null || typeof src !== 'object' || src instanceof Array) ? {} : src
|
|
24
|
-
const
|
|
25
|
-
return { ...srcObject, [
|
|
26
|
-
}
|
|
27
|
-
return
|
|
24
|
+
const { first, tail } = result
|
|
25
|
+
return { ...srcObject, [first]: f(tail)(object.at(first)(srcObject)) }
|
|
26
|
+
}
|
|
27
|
+
return f
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
/** @type {(_: string) => seq.Sequence<string>} */
|
|
31
|
-
const stringSerialize = input =>
|
|
31
|
+
const stringSerialize = input => [JSON.stringify(input)]
|
|
32
32
|
|
|
33
33
|
/** @type {(_: number) => seq.Sequence<string>} */
|
|
34
|
-
const numberSerialize = input =>
|
|
34
|
+
const numberSerialize = input => [JSON.stringify(input)]
|
|
35
35
|
|
|
36
|
-
const nullSerialize =
|
|
36
|
+
const nullSerialize = ['null']
|
|
37
37
|
|
|
38
|
-
const trueSerialize =
|
|
38
|
+
const trueSerialize = ['true']
|
|
39
39
|
|
|
40
|
-
const falseSerialize =
|
|
40
|
+
const falseSerialize = ['false']
|
|
41
41
|
|
|
42
42
|
/** @type {(_: boolean) => seq.Sequence<string>} */
|
|
43
43
|
const boolSerialize = value => value ? trueSerialize : falseSerialize
|
|
44
44
|
|
|
45
|
-
const colon =
|
|
46
|
-
const comma =
|
|
45
|
+
const colon = [':']
|
|
46
|
+
const comma = [',']
|
|
47
47
|
|
|
48
48
|
/** @type {op.Scan<seq.Sequence<string>, seq.Sequence<string>>} */
|
|
49
49
|
const commaValue = a => [seq.concat(comma, a), commaValue]
|
|
50
50
|
|
|
51
|
-
/** @type {
|
|
52
|
-
const
|
|
51
|
+
/** @type {seq.FoldOperator<seq.Sequence<string>>} */
|
|
52
|
+
const joinOp = a => b => seq.concat(a, comma, b)
|
|
53
53
|
|
|
54
|
-
/** @type {seq.
|
|
55
|
-
const join =
|
|
56
|
-
const _0 = seq.scan(joinScan)(input)
|
|
57
|
-
return seq.flat(_0)
|
|
58
|
-
}
|
|
54
|
+
/** @type {(input: seq.Sequence<seq.Sequence<string>>) => seq.Sequence<string>} */
|
|
55
|
+
const join = seq.fold(joinOp)([])
|
|
59
56
|
|
|
60
57
|
/** @type {(open: string) => (close: string) => (input: seq.Sequence<seq.Sequence<string>>) => seq.Sequence<string>} */
|
|
61
58
|
const list = open => close => {
|
|
62
|
-
const seqOpen =
|
|
63
|
-
const seqClose =
|
|
59
|
+
const seqOpen = [open]
|
|
60
|
+
const seqClose = [close]
|
|
64
61
|
return input => seq.concat(seqOpen, join(input), seqClose)
|
|
65
62
|
}
|
|
66
63
|
|
|
@@ -83,15 +80,15 @@ const serialize = sort => {
|
|
|
83
80
|
f(v))
|
|
84
81
|
/** @type {(object: Object) => seq.Sequence<string>} */
|
|
85
82
|
const objectSerialize = input => {
|
|
86
|
-
const entries =
|
|
83
|
+
const entries = Object.entries(input)
|
|
87
84
|
const sortedEntries = sort(entries)
|
|
85
|
+
const _ = seq.toArray(sortedEntries)
|
|
88
86
|
const serializedEntries = seq.map(propertySerialize)(sortedEntries)
|
|
89
87
|
return objectList(serializedEntries)
|
|
90
88
|
}
|
|
91
89
|
/** @type {(input: Array) => seq.Sequence<string>} */
|
|
92
90
|
const arraySerialize = input => {
|
|
93
|
-
const
|
|
94
|
-
const serializedEntries = seq.map(f)(sequence)
|
|
91
|
+
const serializedEntries = seq.map(f)(input)
|
|
95
92
|
return arrayList(serializedEntries)
|
|
96
93
|
}
|
|
97
94
|
/** @type {(value: Json) => seq.Sequence < string >} */
|
|
@@ -118,7 +115,10 @@ const serialize = sort => {
|
|
|
118
115
|
*
|
|
119
116
|
* @type {(mapEntries: MapEntries) => (value: Json) => string}
|
|
120
117
|
*/
|
|
121
|
-
const stringify = sort => value =>
|
|
118
|
+
const stringify = sort => value => {
|
|
119
|
+
const _s = serialize(sort)(value)
|
|
120
|
+
return seq.join('')(_s)
|
|
121
|
+
}
|
|
122
122
|
|
|
123
123
|
/** @type {(value: string) => Json} */
|
|
124
124
|
const parse = value => JSON.parse(value)
|
package/json/test.js
CHANGED
|
@@ -5,7 +5,8 @@ const { identity } = require('../function')
|
|
|
5
5
|
if (json.addProperty("Hello")([])({}) !== "Hello") { throw 'error' }
|
|
6
6
|
|
|
7
7
|
{
|
|
8
|
-
const
|
|
8
|
+
const r = json.addProperty("Hello")(['a'])({})
|
|
9
|
+
const x = json.stringify(sort)(r)
|
|
9
10
|
if (x !== '{"a":"Hello"}') { throw x }
|
|
10
11
|
}
|
|
11
12
|
|
package/map/index.js
CHANGED
|
@@ -56,14 +56,14 @@ const create = root => ({
|
|
|
56
56
|
* @type {{
|
|
57
57
|
* readonly get: (name: string) => undefined
|
|
58
58
|
* readonly set: (name: string) => <T>(value: T) => Map<T>
|
|
59
|
-
* readonly entries:
|
|
59
|
+
* readonly entries: []
|
|
60
60
|
* readonly root: undefined
|
|
61
61
|
* }}
|
|
62
62
|
*/
|
|
63
63
|
const empty = {
|
|
64
64
|
get: () => undefined,
|
|
65
65
|
set: name => value => create([[name, value]]),
|
|
66
|
-
entries:
|
|
66
|
+
entries: [],
|
|
67
67
|
root: undefined
|
|
68
68
|
}
|
|
69
69
|
|
|
@@ -73,7 +73,9 @@ const setOperator = map => ([k, v]) => map.set(k)(v)
|
|
|
73
73
|
/** @type {<T>(entries: seq.Sequence<Entry<T>>) => Map<T>} */
|
|
74
74
|
const fromEntries = entries => {
|
|
75
75
|
/** @typedef {typeof entries extends seq.Sequence<Entry<infer T>> ? T : never} T */
|
|
76
|
-
|
|
76
|
+
/** @type {Map<T>} */
|
|
77
|
+
const init = empty
|
|
78
|
+
return seq.reduce(setOperator)(init)(entries)
|
|
77
79
|
}
|
|
78
80
|
|
|
79
81
|
module.exports = {
|
package/module-manager/index.js
CHANGED
|
@@ -82,15 +82,11 @@ const internal = pack => {
|
|
|
82
82
|
const externalOrInternal = p =>
|
|
83
83
|
p === undefined ? () => undefined : (typeof p === 'function' ? external(p) : internal(p))
|
|
84
84
|
|
|
85
|
-
/** @type {(_: Dependencies) => (
|
|
85
|
+
/** @type {(_: Dependencies) => (path: Path) => Module|undefined} */
|
|
86
86
|
const external = packages => {
|
|
87
87
|
/** @type {(_: readonly [string, Path]) => Module|undefined} */
|
|
88
88
|
const defined = ([first, tail]) => externalOrInternal(packages(first))(tail)
|
|
89
|
-
|
|
90
|
-
const sf = splitFirst
|
|
91
|
-
return compose
|
|
92
|
-
(option.map(defined))
|
|
93
|
-
(sf)
|
|
89
|
+
return path => option.map(defined)(splitFirst(path))
|
|
94
90
|
}
|
|
95
91
|
|
|
96
92
|
/** @type {(_: Location) => (_: string) => Module|undefined} */
|
package/object/index.js
CHANGED
|
@@ -14,9 +14,6 @@ const map = require('../map')
|
|
|
14
14
|
* @typedef {readonly[string, T]} Entry
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
/** @type {<T>(object: Map<T>) => seq.Sequence<Entry<T>>} */
|
|
18
|
-
const entries = object => array.sequence(Object.entries(object))
|
|
19
|
-
|
|
20
17
|
/** @type {(name: string) => <T>(object: Map<T>) => T|undefined} */
|
|
21
18
|
const at = name => object => Object.getOwnPropertyDescriptor(object, name)?.value
|
|
22
19
|
|
|
@@ -24,8 +21,6 @@ const at = name => object => Object.getOwnPropertyDescriptor(object, name)?.valu
|
|
|
24
21
|
const sort = entries => map.fromEntries(entries).entries
|
|
25
22
|
|
|
26
23
|
module.exports = {
|
|
27
|
-
/** @readonly */
|
|
28
|
-
entries,
|
|
29
24
|
/** @readonly */
|
|
30
25
|
at,
|
|
31
26
|
/** @readonly */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "functionalscript",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.222",
|
|
4
4
|
"description": "FunctionalScript is a functional subset of JavaScript",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
},
|
|
20
20
|
"homepage": "https://github.com/functionalscript/functionalscript#readme",
|
|
21
21
|
"devDependencies": {
|
|
22
|
-
"@types/node": "^16.11.
|
|
22
|
+
"@types/node": "^16.11.11",
|
|
23
23
|
"typescript": "^4.5.2"
|
|
24
24
|
}
|
|
25
25
|
}
|
package/sequence/README.md
CHANGED
|
@@ -2,11 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
Sequence types:
|
|
4
4
|
|
|
5
|
+
- Sequence
|
|
5
6
|
- Array
|
|
6
|
-
- List
|
|
7
7
|
- Iterable
|
|
8
8
|
- AsyncIterable
|
|
9
9
|
|
|
10
|
+
# Sequence Types
|
|
11
|
+
|
|
12
|
+
```ts
|
|
13
|
+
type Sequence<T> =
|
|
14
|
+
readonly T[] |
|
|
15
|
+
Thunk<T> |
|
|
16
|
+
|
|
17
|
+
type Thunk<T> = () => Node<T>
|
|
18
|
+
|
|
19
|
+
type Node<T> =
|
|
20
|
+
undefined |
|
|
21
|
+
{ readonly first: T, readonly tail: Sequence<T> } |
|
|
22
|
+
readonly[Sequence<T>, Sequence<T>]
|
|
23
|
+
```
|
|
24
|
+
|
|
10
25
|
## Functions
|
|
11
26
|
|
|
12
27
|
See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array
|
package/sequence/array/index.js
CHANGED
|
@@ -95,21 +95,6 @@ const splitLast = a => {
|
|
|
95
95
|
/** @type {(index: number) => <T>(a: Array<T>) => readonly[T]|undefined} */
|
|
96
96
|
const at = index => a => index < a.length ? [a[index]] : undefined
|
|
97
97
|
|
|
98
|
-
/** @type {<T>(array: Array<T>) => seq.Sequence<T>} */
|
|
99
|
-
const sequence = a => {
|
|
100
|
-
/** @typedef {typeof a extends Array<infer T> ? T : never} T */
|
|
101
|
-
/** @type {(index: number) => seq.Sequence<T>} */
|
|
102
|
-
const seq = index => () => {
|
|
103
|
-
const result = at(index)(a)
|
|
104
|
-
if (result === undefined) { return undefined }
|
|
105
|
-
return [result[0], seq(index + 1)]
|
|
106
|
-
}
|
|
107
|
-
return seq(0)
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/** @type {<T>(list: seq.Sequence<T>) => readonly T[]} */
|
|
111
|
-
const fromSequence = input => Array.from(seq.iterable(input))
|
|
112
|
-
|
|
113
98
|
module.exports = {
|
|
114
99
|
/** @readonly */
|
|
115
100
|
at,
|
|
@@ -125,8 +110,4 @@ module.exports = {
|
|
|
125
110
|
splitFirst,
|
|
126
111
|
/** @readonly */
|
|
127
112
|
splitLast,
|
|
128
|
-
/** @readonly */
|
|
129
|
-
sequence,
|
|
130
|
-
/** @readonly */
|
|
131
|
-
fromSequence,
|
|
132
113
|
}
|
package/sequence/index.js
CHANGED
|
@@ -1,348 +1,327 @@
|
|
|
1
|
-
const seqOp = require('./operator')
|
|
2
1
|
const { compose } = require('../function')
|
|
2
|
+
const { logicalNot, strictEqual, addition } = require('../function/operator')
|
|
3
3
|
const op = require('../function/operator')
|
|
4
|
-
const { logicalNot, strictEqual } = require('../function/operator')
|
|
5
4
|
|
|
6
5
|
/**
|
|
7
6
|
* @template T
|
|
8
|
-
* @typedef {
|
|
7
|
+
* @typedef { readonly T[] | Thunk<T> } Sequence<T>
|
|
9
8
|
*/
|
|
10
9
|
|
|
11
10
|
/**
|
|
12
11
|
* @template T
|
|
13
|
-
* @typedef {
|
|
12
|
+
* @typedef { () => Node<T> } Thunk
|
|
14
13
|
*/
|
|
15
14
|
|
|
16
15
|
/**
|
|
17
|
-
* Use `next` function to get `first` and `tail` of the list.
|
|
18
|
-
*
|
|
19
|
-
* Please note that the sequence 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 workaround, we may have
|
|
22
|
-
* a stack overflow if a list contains a lot of concateneted lists.
|
|
23
|
-
*
|
|
24
16
|
* @template T
|
|
25
|
-
* @typedef {
|
|
17
|
+
* @typedef { Result<T> | Concat<T> } Node<T>
|
|
26
18
|
*/
|
|
27
19
|
|
|
28
20
|
/**
|
|
29
21
|
* @template T
|
|
30
|
-
* @typedef {
|
|
22
|
+
* @typedef { readonly[Sequence<T>, Sequence<T>] } Concat<T>
|
|
31
23
|
*/
|
|
32
24
|
|
|
33
25
|
/**
|
|
34
26
|
* @template T
|
|
35
|
-
* @typedef {
|
|
27
|
+
* @typedef { undefined | ResultOne<T> } Result
|
|
36
28
|
*/
|
|
37
29
|
|
|
38
|
-
const empty = () => undefined
|
|
39
|
-
|
|
40
|
-
/** @type {<T>(first: T) => (tail: Sequence<T>) => Sequence<T>} */
|
|
41
|
-
const sequence = first => tail => () => [first, tail]
|
|
42
|
-
|
|
43
|
-
/** @type {<F, T>(a: readonly[F, Sequence<T>]) => (b: Sequence<T>) => readonly[F, Sequence<T>]} */
|
|
44
|
-
const norm = ([a0, a1]) => b => [a0, [a1, b]]
|
|
45
|
-
|
|
46
|
-
/** @type {<T>(input: Sequence<T>) => Result<T>} */
|
|
47
|
-
const next = input => {
|
|
48
|
-
let i = input
|
|
49
|
-
while (true) {
|
|
50
|
-
if (typeof i === 'function') { return i() }
|
|
51
|
-
const [a, b] = i
|
|
52
|
-
if (typeof a === 'function') {
|
|
53
|
-
const result = a()
|
|
54
|
-
if (result !== undefined) {
|
|
55
|
-
return norm(result)(b)
|
|
56
|
-
}
|
|
57
|
-
i = b
|
|
58
|
-
} else {
|
|
59
|
-
i = norm(a)(b)
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/** @type {<T>(input: Sequence<T>) => T|undefined} */
|
|
65
|
-
const first = input => {
|
|
66
|
-
const result = next(input)
|
|
67
|
-
if (result === undefined) { return undefined }
|
|
68
|
-
return result[0]
|
|
69
|
-
}
|
|
70
|
-
|
|
71
30
|
/**
|
|
72
31
|
* @template T
|
|
73
|
-
* @
|
|
74
|
-
* @typedef {(list: Sequence<T>) => Sequence<R>} SequenceMap
|
|
32
|
+
* @typedef {{ readonly first: T, readonly tail: Sequence<T> }} ResultOne
|
|
75
33
|
*/
|
|
76
34
|
|
|
77
|
-
|
|
78
|
-
* @template T
|
|
79
|
-
* @template R
|
|
80
|
-
* @typedef {(list: Sequence<T>) => R} SequenceReduce
|
|
81
|
-
*/
|
|
35
|
+
const empty = () => undefined
|
|
82
36
|
|
|
83
|
-
/**
|
|
84
|
-
|
|
85
|
-
*
|
|
86
|
-
* @type {<T>(...array: readonly T[]) => Sequence<T>}
|
|
87
|
-
*/
|
|
88
|
-
const list = (...array) => {
|
|
37
|
+
/** @type {<T>(array: readonly T[]) => Result<T>} */
|
|
38
|
+
const fromArray = array => {
|
|
89
39
|
/** @typedef {typeof array extends readonly(infer T)[] ? T : never} T */
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
i = i - 1
|
|
95
|
-
iResult = sequence(array[i])(iResult)
|
|
40
|
+
/** @type {(index: number) => Result<T>} */
|
|
41
|
+
const at = index => {
|
|
42
|
+
if (array.length <= index) { return undefined }
|
|
43
|
+
return { first: array[index], tail: () => at(index + 1) }
|
|
96
44
|
}
|
|
97
|
-
return
|
|
45
|
+
return at(0)
|
|
98
46
|
}
|
|
99
47
|
|
|
100
|
-
/** @type {<T>(
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
48
|
+
/** @type {<T>(sequence: Sequence<T>) => Node<T>} */
|
|
49
|
+
const node = sequence => sequence instanceof Array ? fromArray(sequence) : sequence()
|
|
50
|
+
|
|
51
|
+
/** @type {<T>(concat: Concat<T>) => Sequence<T>} */
|
|
52
|
+
const concatNext = ([a, b]) => {
|
|
53
|
+
const result = node(a)
|
|
54
|
+
if (result === undefined) {
|
|
55
|
+
return b
|
|
56
|
+
} else if (result instanceof Array) {
|
|
57
|
+
const [aa, ab] = result
|
|
58
|
+
return () => [aa, () => [ab, b]]
|
|
59
|
+
} else {
|
|
60
|
+
const { first, tail } = result
|
|
61
|
+
return () => ({ first, tail: () => [tail, b] })
|
|
109
62
|
}
|
|
110
|
-
return result
|
|
111
63
|
}
|
|
112
64
|
|
|
113
|
-
/** @type {(
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
65
|
+
/** @type {<T>(sequence: Sequence<T>) => Result<T>} */
|
|
66
|
+
const next = sequence => {
|
|
67
|
+
let i = sequence
|
|
68
|
+
while (true) {
|
|
69
|
+
const n = node(i)
|
|
70
|
+
if (!(n instanceof Array)) { return n }
|
|
71
|
+
i = concatNext(n)
|
|
119
72
|
}
|
|
120
|
-
return f(0)
|
|
121
73
|
}
|
|
122
74
|
|
|
123
|
-
/** @type {<T
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
75
|
+
/** @type {<T>(sequence: Sequence<T>) => Iterable<T>} */
|
|
76
|
+
const iterable = sequence => ({
|
|
77
|
+
*[Symbol.iterator]() {
|
|
78
|
+
let i = sequence
|
|
79
|
+
while (true) {
|
|
80
|
+
if (i instanceof Array) { return yield *i }
|
|
81
|
+
const n = next(i)
|
|
82
|
+
if (n === undefined) { return }
|
|
83
|
+
const { first, tail } = n
|
|
84
|
+
yield first
|
|
85
|
+
i = tail
|
|
133
86
|
}
|
|
134
|
-
i = tail
|
|
135
87
|
}
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
/** @type {<T>(sequence: Sequence<T>) => readonly T[]} */
|
|
91
|
+
const toArray = sequence => {
|
|
92
|
+
if (sequence instanceof Array) { return sequence }
|
|
93
|
+
return Array.from(iterable(sequence))
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** @type {<I, O>(f: (result: ResultOne<I>) => Node<O>) => (input: Sequence<I>) => Thunk<O>} */
|
|
97
|
+
const nextMap = f => input => () => {
|
|
98
|
+
const n = next(input)
|
|
99
|
+
if (n === undefined) { return undefined }
|
|
100
|
+
return f(n)
|
|
136
101
|
}
|
|
137
102
|
|
|
138
|
-
/** @type {<T>(
|
|
139
|
-
const
|
|
103
|
+
/** @type {<T>(result: ResultOne<Sequence<T>>) => Node<T>} */
|
|
104
|
+
const flatFn = ({first, tail}) => [first, flat(tail)]
|
|
140
105
|
|
|
141
|
-
/** @type {<T
|
|
142
|
-
const
|
|
106
|
+
/** @type {<T>(sequence: Sequence<Sequence<T>>) => Thunk<T>} */
|
|
107
|
+
const flat = nextMap(flatFn)
|
|
143
108
|
|
|
144
|
-
/** @type {<T>(
|
|
145
|
-
const
|
|
109
|
+
/** @type {<T>(...array: readonly Sequence<T>[]) => Thunk<T>} */
|
|
110
|
+
const concat = (...array) => flat(array)
|
|
146
111
|
|
|
147
|
-
/** @type {<
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
112
|
+
/** @type {<I, O>(f: (value: I) => O) => (result: ResultOne<I>) => Node<O>} */
|
|
113
|
+
const mapFn = f => ({ first, tail }) => ({ first: f(first), tail: map(f)(tail) })
|
|
114
|
+
|
|
115
|
+
/** @type {<I, O>(f: (value: I) => O) => (input: Sequence<I>) => Thunk<O>} */
|
|
116
|
+
const map = f => nextMap(mapFn(f))
|
|
117
|
+
|
|
118
|
+
/** @type {<I, O>(f: (value: I) => Sequence<O>) => (input: Sequence<I>) => Thunk<O>} */
|
|
119
|
+
const flatMap = f => compose(map(f))(flat)
|
|
120
|
+
|
|
121
|
+
/** @type {<T>(f: (value: T) => boolean) => (result: ResultOne<T>) => Node<T>} */
|
|
122
|
+
const filterFn = f => ({ first, tail }) => {
|
|
123
|
+
const fTail = filter(f)(tail)
|
|
124
|
+
return f(first) ? { first, tail: fTail } : fTail()
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** @type {<T>(f: (value: T) => boolean) => (input: Sequence<T>) => Thunk<T>} */
|
|
128
|
+
const filter = f => nextMap(filterFn(f))
|
|
129
|
+
|
|
130
|
+
/** @type {<I, O>(f: (value: I) => O|undefined) => (result: ResultOne<I>) => Node<O>} */
|
|
131
|
+
const filterMapFn = f => ({first, tail}) => {
|
|
132
|
+
const fFirst = f(first)
|
|
133
|
+
const fTail = filterMap(f)(tail)
|
|
134
|
+
return fFirst === undefined ? fTail() : { first: fFirst, tail: fTail }
|
|
152
135
|
}
|
|
153
136
|
|
|
154
|
-
/** @type {<
|
|
155
|
-
const filterMap = f =>
|
|
137
|
+
/** @type {<I, O>(f: (value: I) => O|undefined) => (input: Sequence<I>) => Thunk<O>} */
|
|
138
|
+
const filterMap = f => nextMap(filterMapFn(f))
|
|
156
139
|
|
|
157
|
-
/** @type {<T
|
|
158
|
-
const
|
|
140
|
+
/** @type {<T>(f: (value: T) => boolean) => (input: Sequence<T>) => Thunk<T>} */
|
|
141
|
+
const takeWhile = f => input => () => {
|
|
159
142
|
const result = next(input)
|
|
160
|
-
if (result === undefined) {
|
|
161
|
-
|
|
143
|
+
if (result === undefined) { return undefined }
|
|
144
|
+
const { first, tail } = result
|
|
145
|
+
if (!f(first)) { return undefined }
|
|
146
|
+
return { first, tail: takeWhile(f)(result.tail) }
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** @type {<T>(f: (value: T) => boolean) => (input: Sequence<T>) => Thunk<T>} */
|
|
150
|
+
const dropWhile = f => input => () => {
|
|
151
|
+
let i = input
|
|
152
|
+
while (true) {
|
|
153
|
+
const result = next(i)
|
|
154
|
+
if (result === undefined) { return undefined }
|
|
155
|
+
const { first, tail } = result
|
|
156
|
+
if (!f(first)) return result
|
|
157
|
+
i = tail
|
|
162
158
|
}
|
|
163
|
-
const [first, tail] = result
|
|
164
|
-
const [newFirst, newS] = s(first)
|
|
165
|
-
return [newFirst, scan(newS)(tail)]
|
|
166
159
|
}
|
|
167
160
|
|
|
168
|
-
/** @type {<T
|
|
169
|
-
const
|
|
161
|
+
/** @type {<D>(def: D) => <T>(input: Sequence<T>) => D|T} */
|
|
162
|
+
const first = def => input => {
|
|
163
|
+
const result = next(input)
|
|
164
|
+
if (result === undefined) { return def }
|
|
165
|
+
return result.first
|
|
166
|
+
}
|
|
170
167
|
|
|
171
|
-
/** @type {<
|
|
168
|
+
/** @type {<D>(def: D) => <T>(input: Sequence<T>) => D|T} */
|
|
172
169
|
const last = def => input => {
|
|
170
|
+
/** @typedef {typeof input extends Sequence<infer T> ? T : never} T */
|
|
171
|
+
/** @type {(typeof def)|T} */
|
|
173
172
|
let r = def
|
|
174
|
-
let i = input
|
|
173
|
+
let i = input
|
|
175
174
|
while (true) {
|
|
176
175
|
const result = next(i)
|
|
177
176
|
if (result === undefined) {
|
|
178
177
|
return r
|
|
179
178
|
}
|
|
180
|
-
r = result
|
|
181
|
-
i = result
|
|
179
|
+
r = result.first
|
|
180
|
+
i = result.tail
|
|
182
181
|
}
|
|
183
182
|
}
|
|
184
183
|
|
|
185
|
-
/** @type {<
|
|
186
|
-
const
|
|
184
|
+
/** @type {<D>(def: D) => <T>(f: (value: T) => boolean) => (sequence: Sequence<T>) => D|T} */
|
|
185
|
+
const find = def => f => input => first(def)(filter(f)(input))
|
|
187
186
|
|
|
188
|
-
/** @type {<T
|
|
189
|
-
const
|
|
187
|
+
/** @type {<T>(f: (value: T) => boolean) => (sequence: Sequence<T>) => boolean} */
|
|
188
|
+
const some = f => input => find(false)(x => x)(map(f)(input))
|
|
190
189
|
|
|
191
|
-
|
|
190
|
+
/** @type {<T>(f: (value: T) => boolean) => (sequence: Sequence<T>) => boolean} */
|
|
191
|
+
const every = f => input => !some(compose(f)(logicalNot))(input)
|
|
192
192
|
|
|
193
|
-
|
|
193
|
+
/** @type {<T>(value: T) => (sequence: Sequence<T>) => boolean} */
|
|
194
|
+
const includes = value => some(strictEqual(value))
|
|
194
195
|
|
|
195
|
-
|
|
196
|
+
/** @type {(count: number) => Thunk<number>} */
|
|
197
|
+
const countdown = count => () => {
|
|
198
|
+
if (count <= 0) { return undefined }
|
|
199
|
+
const first = count - 1
|
|
200
|
+
return { first, tail: countdown(first) }
|
|
201
|
+
}
|
|
196
202
|
|
|
197
|
-
/**
|
|
198
|
-
|
|
203
|
+
/**
|
|
204
|
+
* @template T,A
|
|
205
|
+
* @typedef {(value: T) => ScanState<T, A>} ScanFunc
|
|
206
|
+
*/
|
|
199
207
|
|
|
200
|
-
/**
|
|
201
|
-
|
|
208
|
+
/**
|
|
209
|
+
* @template T,A
|
|
210
|
+
* @typedef {readonly[A, ScanFunc<T, A>]} ScanState
|
|
211
|
+
*/
|
|
212
|
+
|
|
213
|
+
/** @type {<T,A>(operator: ScanFunc<T, A>) => (input: Sequence<T>) => Thunk<A>} */
|
|
214
|
+
const scan = operator => input => () => {
|
|
202
215
|
const result = next(input)
|
|
203
|
-
if (result === undefined
|
|
204
|
-
|
|
216
|
+
if (result === undefined) { return undefined }
|
|
217
|
+
const { first, tail } = result
|
|
218
|
+
const r = operator(first)
|
|
219
|
+
return { first: r[0], tail: scan(r[1])(tail) }
|
|
205
220
|
}
|
|
206
221
|
|
|
207
|
-
/** @type {(
|
|
208
|
-
const
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
222
|
+
/** @type {<T,A>(operator: ScanFunc<T, A>) => <D>(def: D)=> (input: Sequence<T>) => D|A} */
|
|
223
|
+
const scanReduce = operator => def => input => last(def)(scan(operator)(input))
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* @template T,A
|
|
227
|
+
* @typedef {(prior: A) => (value: T) => A} ReduceOperator
|
|
228
|
+
*/
|
|
229
|
+
|
|
230
|
+
/** @type {<T,A>(operator: ReduceOperator<T, A>) => (init: A) => ScanState<T, A>} */
|
|
231
|
+
const scanState = operator => init => [init, scanFunc(operator)(init)]
|
|
232
|
+
|
|
233
|
+
/** @type {<T,A>(operator: ReduceOperator<T, A>) => (init: A) => ScanFunc<T, A>} */
|
|
234
|
+
const scanFunc = operator => init => value => {
|
|
235
|
+
const result = operator(init)(value)
|
|
236
|
+
return scanState(operator)(result)
|
|
217
237
|
}
|
|
218
238
|
|
|
219
|
-
/** @type {(
|
|
220
|
-
const
|
|
239
|
+
/** @type {<T,A>(operator: ReduceOperator<T, A>) => (init: A) => (input: Sequence<T>) => A} */
|
|
240
|
+
const reduce = operator => init => scanReduce(scanFunc(operator)(init))(init)
|
|
221
241
|
|
|
222
|
-
/**
|
|
223
|
-
|
|
242
|
+
/**
|
|
243
|
+
* @template T
|
|
244
|
+
* @typedef {ReduceOperator<T, T>} FoldOperator
|
|
245
|
+
*/
|
|
224
246
|
|
|
225
|
-
/** @type {<T>(
|
|
226
|
-
const
|
|
247
|
+
/** @type {<T>(operator: FoldOperator<T>) => <D>(def: D) => (input: Sequence<T>) => D|T} */
|
|
248
|
+
const fold = operator => def => scanReduce(scanState(operator))(def)
|
|
227
249
|
|
|
228
|
-
|
|
229
|
-
const includes = value => some(strictEqual(value))
|
|
250
|
+
const sum = fold(addition)(0)
|
|
230
251
|
|
|
231
|
-
/** @type {
|
|
232
|
-
const
|
|
252
|
+
/** @type {(separator: string) => (input: Sequence<string>) => string} */
|
|
253
|
+
const join = separator => fold(op.join(separator))('')
|
|
233
254
|
|
|
234
|
-
/** @type {
|
|
235
|
-
const
|
|
236
|
-
*[Symbol.iterator]() {
|
|
237
|
-
let i = list
|
|
238
|
-
while (true) {
|
|
239
|
-
const result = next(i)
|
|
240
|
-
if (result === undefined) { return }
|
|
241
|
-
yield result[0]
|
|
242
|
-
i = result[1]
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
})
|
|
255
|
+
/** @type {(a: number) => () => number} */
|
|
256
|
+
const counter = a => () => a + 1
|
|
246
257
|
|
|
247
|
-
/** @type {<T>(
|
|
248
|
-
const
|
|
249
|
-
async *[Symbol.asyncIterator]() {
|
|
250
|
-
let i = list
|
|
251
|
-
while (true) {
|
|
252
|
-
const result = next(i)
|
|
253
|
-
if (result === undefined) { return }
|
|
254
|
-
yield result[0]
|
|
255
|
-
i = result[1]
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
})
|
|
258
|
+
/** @type {<T>(input: Sequence<T>) => number} */
|
|
259
|
+
const length = reduce(counter)(0)
|
|
259
260
|
|
|
260
|
-
/**
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
const resultB = next(b)
|
|
265
|
-
if (resultB === undefined) { return undefined }
|
|
266
|
-
return [[resultA[0], resultB[0]], zip(resultA[1])(resultB[1])]
|
|
267
|
-
}
|
|
261
|
+
/**
|
|
262
|
+
* @template T
|
|
263
|
+
* @typedef {readonly[number, T]} Entry
|
|
264
|
+
*/
|
|
268
265
|
|
|
269
|
-
/** @type {<T>(
|
|
270
|
-
const
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
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
|
-
}
|
|
266
|
+
/** @type {(index: number) => <T>(value: T) => ScanState<T, Entry<T>>} */
|
|
267
|
+
const entryOp = index => value => [[index, value], entryOp(index + 1)]
|
|
268
|
+
|
|
269
|
+
/** @type {<T>(input: Sequence<T>) => Thunk<Entry<T>>} */
|
|
270
|
+
const entries = scan(entryOp(0))
|
|
282
271
|
|
|
283
272
|
module.exports = {
|
|
284
273
|
/** @readonly */
|
|
285
|
-
|
|
274
|
+
empty,
|
|
286
275
|
/** @readonly */
|
|
287
|
-
|
|
276
|
+
iterable,
|
|
288
277
|
/** @readonly */
|
|
289
|
-
|
|
278
|
+
next,
|
|
279
|
+
/** @readonly */
|
|
280
|
+
toArray,
|
|
290
281
|
/** @readonly */
|
|
291
|
-
|
|
282
|
+
flat,
|
|
292
283
|
/** @readonly */
|
|
293
|
-
|
|
284
|
+
last,
|
|
294
285
|
/** @readonly */
|
|
295
286
|
concat,
|
|
296
287
|
/** @readonly */
|
|
297
|
-
generate,
|
|
298
|
-
/** @readonly */
|
|
299
288
|
first,
|
|
300
289
|
/** @readonly */
|
|
301
|
-
|
|
302
|
-
/** @readonly */
|
|
303
|
-
asyncIterable,
|
|
290
|
+
map,
|
|
304
291
|
/** @readonly */
|
|
305
292
|
flatMap,
|
|
306
293
|
/** @readonly */
|
|
307
|
-
flat,
|
|
308
|
-
/** @readonly */
|
|
309
|
-
map,
|
|
310
|
-
/** @readonly */
|
|
311
294
|
filter,
|
|
312
295
|
/** @readonly */
|
|
313
|
-
|
|
314
|
-
/** @readonly */
|
|
315
|
-
scan,
|
|
316
|
-
/** @readonly */
|
|
317
|
-
exclusiveScan,
|
|
296
|
+
find,
|
|
318
297
|
/** @readonly */
|
|
319
|
-
|
|
298
|
+
some,
|
|
320
299
|
/** @readonly */
|
|
321
|
-
|
|
300
|
+
every,
|
|
322
301
|
/** @readonly */
|
|
323
|
-
|
|
302
|
+
includes,
|
|
324
303
|
/** @readonly */
|
|
325
|
-
|
|
304
|
+
takeWhile,
|
|
326
305
|
/** @readonly */
|
|
327
|
-
|
|
306
|
+
dropWhile,
|
|
328
307
|
/** @readonly */
|
|
329
|
-
|
|
308
|
+
scanFunc,
|
|
330
309
|
/** @readonly */
|
|
331
|
-
|
|
310
|
+
scanState,
|
|
332
311
|
/** @readonly */
|
|
333
|
-
|
|
312
|
+
scan,
|
|
334
313
|
/** @readonly */
|
|
335
|
-
|
|
314
|
+
reduce,
|
|
336
315
|
/** @readonly */
|
|
337
|
-
|
|
316
|
+
fold,
|
|
338
317
|
/** @readonly */
|
|
339
|
-
|
|
318
|
+
sum,
|
|
340
319
|
/** @readonly */
|
|
341
|
-
|
|
320
|
+
join,
|
|
342
321
|
/** @readonly */
|
|
343
|
-
|
|
322
|
+
entries,
|
|
344
323
|
/** @readonly */
|
|
345
|
-
|
|
324
|
+
length,
|
|
346
325
|
/** @readonly */
|
|
347
|
-
|
|
348
|
-
}
|
|
326
|
+
countdown,
|
|
327
|
+
}
|
|
@@ -39,7 +39,7 @@ const sum = reduce(seq.sum)
|
|
|
39
39
|
|
|
40
40
|
const length = reduce(seq.length)
|
|
41
41
|
|
|
42
|
-
const join = compose(
|
|
42
|
+
const join = compose(seq.join)(reduce)
|
|
43
43
|
|
|
44
44
|
/** @type {<T, R>(f: (value: T) => Iterable<R>) => (c: Iterable<T>) => Iterable<R>} */
|
|
45
45
|
const flatMap = f => c => ({
|
|
@@ -34,8 +34,8 @@ const { compose } = require('../../function')
|
|
|
34
34
|
const file = _ => 'x'
|
|
35
35
|
/** @type {(_: string) => string|undefined} */
|
|
36
36
|
const x = p => compose
|
|
37
|
-
(i.
|
|
38
|
-
(i.
|
|
37
|
+
(i.map(x => file(x())))
|
|
38
|
+
(i.find(x => x !== undefined))
|
|
39
39
|
([() => p, () => `${p}.js`, () => `${p}/index.js`])
|
|
40
40
|
if (x('index.js') !== 'x') { throw 'error' }
|
|
41
41
|
}
|
|
@@ -35,7 +35,7 @@ const scan = operator => {
|
|
|
35
35
|
return [result, f(result)]
|
|
36
36
|
}
|
|
37
37
|
return f
|
|
38
|
-
}
|
|
38
|
+
}
|
|
39
39
|
|
|
40
40
|
/** @type {<R, T>(operator: op.ReduceOperator<R, T>) => (first: R) => ExclusiveScan<T, R>} */
|
|
41
41
|
const exclusiveScan = operator => first => [first, scan(operator)(first)]
|
package/sequence/test.js
CHANGED
|
@@ -1,75 +1,142 @@
|
|
|
1
|
-
const
|
|
2
|
-
const { empty, next, list, flatMap, concat, exclusiveScan, find, every, some, first, drop, map, generate } = require('.')
|
|
3
|
-
const { sum } = require('./operator')
|
|
4
|
-
const array = require('./array')
|
|
1
|
+
const _ = require('.')
|
|
5
2
|
const json = require('../json')
|
|
6
|
-
const {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
3
|
+
const { sort } = require('../object')
|
|
4
|
+
const { addition } = require('../function/operator')
|
|
5
|
+
|
|
6
|
+
/** @type {(sequence: _.Sequence<json.Json>) => string} */
|
|
7
|
+
const stringify = sequence => json.stringify(sort)(_.toArray(sequence))
|
|
8
|
+
|
|
9
|
+
{
|
|
10
|
+
const s = stringify([1, 2, 3])
|
|
11
|
+
if (s !== '[1,2,3]') { throw s }
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
{
|
|
15
|
+
const result = stringify(_.countdown(10))
|
|
16
|
+
if (result !== '[9,8,7,6,5,4,3,2,1,0]') { throw result }
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
{
|
|
20
|
+
const result = stringify(_.concat([1, 2, 3], [4, 5], [6], [], [7, 8, 9]))
|
|
21
|
+
if (result !== '[1,2,3,4,5,6,7,8,9]') { throw result }
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
{
|
|
25
|
+
const result = _.concat([1], [2])
|
|
26
|
+
const x = _.next(result)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
{
|
|
30
|
+
const result = stringify(_.flatMap(x => [x, x * 2, x * 3])([0, 1, 2, 3]))
|
|
31
|
+
if (result !== '[0,0,0,1,2,3,2,4,6,3,6,9]') { throw result }
|
|
17
32
|
}
|
|
18
33
|
|
|
19
34
|
{
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const
|
|
26
|
-
if (
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
35
|
+
const result = stringify(_.takeWhile(x => x < 6)([1, 2, 3, 4, 5, 6, 7, 8, 9]))
|
|
36
|
+
if (result !== '[1,2,3,4,5]') { throw result }
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
{
|
|
40
|
+
const result = _.find(undefined)(x => x % 2 === 0)([1, 2, 3, 4])
|
|
41
|
+
if (result !== 2) { throw result }
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
{
|
|
45
|
+
const result = stringify(_.takeWhile(x => x < 10)([1, 2, 3, 4, 5, 10, 11]))
|
|
46
|
+
if (result !== '[1,2,3,4,5]') { throw result }
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
{
|
|
50
|
+
const result = stringify(_.dropWhile(x => x < 10)([1, 2, 3, 4, 5, 10, 11]))
|
|
51
|
+
if (result !== '[10,11]') { throw result }
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
{
|
|
55
|
+
const op = _.scanState(addition)
|
|
56
|
+
const result = stringify(_.scan(op)([2, 3, 4, 5]))
|
|
57
|
+
if (result !== '[2,5,9,14]') { throw result }
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
{
|
|
61
|
+
const result = _.sum([2, 3, 4, 5])
|
|
62
|
+
if (result !== 14) { throw result }
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
{
|
|
66
|
+
const result = _.fold(addition)(undefined)([2, 3, 4, 5])
|
|
67
|
+
if (result !== 14) { throw result }
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
{
|
|
71
|
+
const result = _.fold(addition)(undefined)([])
|
|
72
|
+
if (result !== undefined) { throw result }
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
{
|
|
76
|
+
const result = _.join('/')([])
|
|
77
|
+
if (result !== '') { throw result }
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
{
|
|
81
|
+
const result = _.join('/')([''])
|
|
82
|
+
if (result !== '') { throw result }
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
{
|
|
86
|
+
const result = stringify(_.entries([]))
|
|
87
|
+
if (result !== '[]') { throw result }
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
{
|
|
91
|
+
const result = stringify(_.entries(['hello', 'world']))
|
|
92
|
+
if (result !== '[[0,"hello"],[1,"world"]]') { throw result }
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// stress tests
|
|
96
|
+
|
|
97
|
+
const stress = () => {
|
|
31
98
|
{
|
|
32
|
-
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const r = next(x)
|
|
39
|
-
// print(x)
|
|
99
|
+
// 200_000_000 is too much
|
|
100
|
+
const n = 100_000_000
|
|
101
|
+
const result = _.toArray(_.countdown(n))
|
|
102
|
+
if (result.length !== n) { throw result.length }
|
|
103
|
+
const first = _.first(undefined)(result)
|
|
104
|
+
if (first !== n - 1) { throw first }
|
|
40
105
|
}
|
|
106
|
+
|
|
41
107
|
{
|
|
42
|
-
|
|
43
|
-
let
|
|
44
|
-
|
|
45
|
-
|
|
108
|
+
/** @type {_.Sequence<number>} */
|
|
109
|
+
let sequence = []
|
|
110
|
+
// 2_000_000 is too much
|
|
111
|
+
for (let i = 0; i < 1_000_000; ++i) {
|
|
112
|
+
sequence = _.concat(sequence, [i])
|
|
113
|
+
}
|
|
114
|
+
const r = _.toArray(sequence)
|
|
46
115
|
}
|
|
116
|
+
|
|
47
117
|
{
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
118
|
+
/** @type {_.Sequence<number>} */
|
|
119
|
+
let sequence = []
|
|
120
|
+
// 5_000_000 is too much
|
|
121
|
+
for (let i = 0; i < 2_000_000; ++i) {
|
|
122
|
+
sequence = _.concat(sequence, [i])
|
|
51
123
|
}
|
|
52
|
-
const
|
|
53
|
-
// print(x)
|
|
124
|
+
const a = _.next(sequence)
|
|
54
125
|
}
|
|
126
|
+
|
|
55
127
|
{
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
128
|
+
/** @type {_.Sequence<number>} */
|
|
129
|
+
let sequence = []
|
|
130
|
+
// 10_000_000 is too much
|
|
131
|
+
for (let i = 0; i < 5_000_000; ++i) {
|
|
132
|
+
sequence = _.concat([i], sequence)
|
|
59
133
|
}
|
|
60
|
-
const
|
|
61
|
-
// print(x)
|
|
134
|
+
const a = _.next(sequence)
|
|
62
135
|
}
|
|
63
136
|
}
|
|
64
137
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
138
|
+
stress()
|
|
139
|
+
|
|
140
|
+
module.exports = {
|
|
69
141
|
|
|
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
142
|
}
|
package/test.js
CHANGED
|
@@ -82,14 +82,14 @@ const assert_if = c => { if (c) { throw 'assert_if' } }
|
|
|
82
82
|
constructor: undefined
|
|
83
83
|
}
|
|
84
84
|
const c = o['constructor']
|
|
85
|
-
console.log(c)
|
|
85
|
+
//console.log(c)
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
{
|
|
89
89
|
/** @type {any} */
|
|
90
90
|
const b = '42'
|
|
91
91
|
const r = Number(b)
|
|
92
|
-
console.log(r)
|
|
92
|
+
//console.log(r)
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
{
|
|
@@ -106,7 +106,7 @@ const assert_if = c => { if (c) { throw 'assert_if' } }
|
|
|
106
106
|
//const c = o['propertyIsEnumerable']
|
|
107
107
|
//const c = o['toString']
|
|
108
108
|
const c = o['valueOf']
|
|
109
|
-
console.log(c)
|
|
109
|
+
//console.log(c)
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
{
|
|
@@ -1,41 +0,0 @@
|
|
|
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
|
-
```
|