functionalscript 0.0.185 → 0.0.191

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 CHANGED
@@ -1,6 +1,5 @@
1
1
  const { index3, index5 } = require('../cmp')
2
- const list = require('../sequence/list')
3
- const { pipe } = require('../function')
2
+ const seq = require('../sequence')
4
3
 
5
4
  /**
6
5
  * @template T
@@ -306,64 +305,33 @@ const replaceVisitor = {
306
305
  notFound: notFoundGet,
307
306
  }
308
307
 
309
- /** @type {<T>(_: Node<T>) => Iterable<T>} */
310
- const values = node => ({
311
- *[Symbol.iterator]() {
312
- switch (node.length) {
313
- case 1: case 2: {
314
- yield* node
315
- return
316
- }
317
- case 3: {
318
- yield* values(node[0])
319
- yield node[1]
320
- yield* values(node[2])
321
- return
322
- }
323
- default: {
324
- yield* values(node[0])
325
- yield node[1]
326
- yield* values(node[2])
327
- yield node[3]
328
- yield* values(node[4])
329
- return
330
- }
331
- }
332
- }
333
- })
334
-
335
- /** @type {<T>(...array: readonly list.List<T>[]) => list.List<T>} */
336
- const flatArray = (...array) => list.flat(list.fromArray(array))
337
-
338
- /** @type {<T>(node: Node<T>) => list.List<T>} */
339
- const valuesList = node => () => {
308
+ /** @type {<T>(node: Node<T>) => seq.Sequence<T>} */
309
+ const values = node => () => {
340
310
  const f = () => {
341
311
  switch (node.length) {
342
- case 1: case 2: { return list.fromArray(node) }
312
+ case 1: case 2: { return seq.list(...node) }
343
313
  case 3: {
344
- return flatArray(
345
- valuesList(node[0]),
346
- list.one(node[1]),
347
- valuesList(node[2])
314
+ return seq.concat(
315
+ values(node[0]),
316
+ seq.list(node[1]),
317
+ values(node[2])
348
318
  )
349
319
  }
350
320
  default: {
351
- return flatArray(
352
- valuesList(node[0]),
353
- list.one(node[1]),
354
- valuesList(node[2]),
355
- list.one(node[3]),
356
- valuesList(node[4])
321
+ return seq.concat(
322
+ values(node[0]),
323
+ seq.list(node[1]),
324
+ values(node[2]),
325
+ seq.list(node[3]),
326
+ values(node[4])
357
327
  )
358
328
  }
359
329
  }
360
330
  }
361
- return list.next(f())
331
+ return seq.next(f())
362
332
  }
363
333
 
364
334
  module.exports = {
365
- /** @readonly */
366
- valuesList,
367
335
  /** @readonly */
368
336
  values,
369
337
  /**
package/btree/test.js CHANGED
@@ -1,7 +1,7 @@
1
1
  const btree = require('.')
2
- const { setVisitor, valuesList } = btree
2
+ const { setVisitor, values: valuesList } = btree
3
3
  const { cmp } = require('../cmp')
4
- const list = require('../sequence/list')
4
+ const list = require('../sequence')
5
5
 
6
6
  /** @type {(node: btree.Node<string>) => (value: string) => btree.Node<string>} */
7
7
  const set = node => value => {
@@ -21,11 +21,9 @@ const test = () => {
21
21
  node = set(node)('f')
22
22
  //
23
23
  {
24
- /** @type {import('../sequence/list').Result<string>} */
24
+ /** @type {import('../sequence').Result<string>} */
25
25
  let result = list.next(valuesList(node))
26
26
  while (result !== undefined) {
27
- const t = result[0]
28
- console.log(t)
29
27
  result = list.next(result[1])
30
28
  }
31
29
  }
package/json/index.js ADDED
@@ -0,0 +1,89 @@
1
+ const seq = require('../sequence')
2
+ const map = require('../map')
3
+ const op = require('../sequence/operator')
4
+
5
+ /**
6
+ * @typedef {{
7
+ * readonly [k in string]: Json
8
+ * }} Object
9
+ */
10
+
11
+ /** @typedef {readonly Json[]} Array */
12
+
13
+ /** @typedef {Object|boolean|string|number|null|Array} Json */
14
+
15
+ /** @type {(value: Json) => (path: readonly string[]) => (src: Json|undefined) => Json} */
16
+ const addProperty = value => {
17
+ /** @type {(path: seq.Sequence<string>) => (src: Json|undefined) => Json} */
18
+ const f = path => src => {
19
+ const result = seq.next(path)
20
+ if (result === undefined) { return value }
21
+ const srcObject = (src === undefined || src === null || typeof src !== 'object' || src instanceof Array) ? {} : src
22
+ const [name, tail] = result
23
+ return { ...srcObject, [name]: f(tail)(srcObject[name]) }
24
+ }
25
+ return path => f(seq.fromArray(path))
26
+ }
27
+
28
+ /** @type {(kv: readonly[string, seq.Sequence<string>]) => seq.Sequence<string>} */
29
+ const property = ([k, v]) => seq.concat(seq.list(JSON.stringify(k)), seq.list(':'), v)
30
+
31
+ /** @type {op.Scan<seq.Sequence<string>, seq.Sequence<string>>} */
32
+ const commaValue = a => [seq.concat(seq.list(','), a), commaValue]
33
+
34
+ /** @type {op.Scan<seq.Sequence<string>, seq.Sequence<string>>} */
35
+ const joinScan = value => [value, commaValue]
36
+
37
+ /** @type {seq.SequenceMap<seq.Sequence<string>, string>} */
38
+ const join = input => seq.flat(seq.scan(joinScan)(input))
39
+
40
+ /** @type {(open: string) => (close: string) => (input: seq.Sequence<seq.Sequence<string>>) => seq.Sequence<string>} */
41
+ const list = open => close => {
42
+ const seqOpen = seq.list(open)
43
+ const seqClose = seq.list(close)
44
+ return input => seq.concat(seqOpen, join(input), seqClose)
45
+ }
46
+
47
+ const objectList = list('{')('}')
48
+
49
+ const arrayList = list('[')(']')
50
+
51
+ /** @type {(object: Object) => seq.Sequence<string>} */
52
+ const objectStringify = object => {
53
+ /** @type {map.Map<seq.Sequence<string>>} */
54
+ const m = seq.fold(m => ([k, v]) => m.set(k)(stringSeq(v)))(map.empty)(seq.fromArray(Object.entries(object)))
55
+ return objectList(seq.map(property)(m.entries))
56
+ }
57
+
58
+ /** @type {(array: Array) => seq.Sequence<string>} */
59
+ const arrayStringify = array => arrayList(seq.map(stringSeq)(seq.fromArray(array)))
60
+
61
+ /** @type {(value: Json) => seq.Sequence<string>} */
62
+ const stringSeq = value => {
63
+ const x = typeof value
64
+ switch (typeof value) {
65
+ case 'boolean': { return seq.list(value ? "true" : "false") }
66
+ // Note: we shouldn't use JSON.stringify since it has non determenistic behavior.
67
+ // In particular: property order could be different.
68
+ case 'number': case 'string': { return seq.list(JSON.stringify(value)) }
69
+ default: {
70
+ if (value === null) { return seq.list("null") }
71
+ if (value instanceof Array) { return arrayStringify(value) }
72
+ return objectStringify(value)
73
+ }
74
+ }
75
+ }
76
+
77
+ /**
78
+ * A deterministic version of `JSON.stringify`
79
+ *
80
+ * @type {(value: Json) => string}
81
+ */
82
+ const stringify = value => seq.join('')(stringSeq(value))
83
+
84
+ module.exports = {
85
+ /** @readonly */
86
+ addProperty,
87
+ /** @readonly */
88
+ stringify,
89
+ }
package/json/test.js ADDED
@@ -0,0 +1,18 @@
1
+ const json = require('.')
2
+
3
+ if (json.addProperty("Hello")([])({}) !== "Hello") { throw 'error' }
4
+
5
+ {
6
+ const x = json.stringify(json.addProperty("Hello")(['a'])({}))
7
+ if (x !== '{"a":"Hello"}') { throw x }
8
+ }
9
+
10
+ {
11
+ const x = json.stringify(json.addProperty("Hello")(['a'])({c:[],b:12}))
12
+ if (x !== '{"a":"Hello","b":12,"c":[]}') { throw x }
13
+ }
14
+
15
+ {
16
+ const x = json.stringify(json.addProperty("Hello")(['a', 'x'])({ a: { y: [24] }, c: [], b: 12 }))
17
+ if (x !== '{"a":{"x":"Hello","y":[24]},"b":12,"c":[]}') { throw x }
18
+ }
package/map/index.js CHANGED
@@ -1,7 +1,8 @@
1
1
  const option = require("../option")
2
- const { getVisitor, setVisitor, valuesList } = require("../btree")
2
+ const { getVisitor, setVisitor, values: valuesList } = require("../btree")
3
3
  const { cmp } = require("../cmp")
4
- const list = require("../sequence/list")
4
+ const seq = require("../sequence")
5
+ const op = require("../sequence/operator")
5
6
 
6
7
  /** @typedef {import("../cmp").Sign} Sign */
7
8
 
@@ -30,7 +31,7 @@ const list = require("../sequence/list")
30
31
  * @typedef {{
31
32
  * readonly get: (name: string) => T|undefined
32
33
  * readonly set: (name: string) => (value: T) => Map<T>
33
- * readonly entries: list.List<Entry<T>>
34
+ * readonly entries: seq.Sequence<Entry<T>>
34
35
  * readonly root: undefined|TNode<Entry<T>>
35
36
  * }} Map
36
37
  */
@@ -62,11 +63,16 @@ const create = root => ({
62
63
  const empty = {
63
64
  get: () => undefined,
64
65
  set: name => value => create([[name, value]]),
65
- entries: list.empty,
66
+ entries: seq.empty,
66
67
  root: undefined
67
68
  }
68
69
 
70
+ /** @type {<T>(entries: seq.Sequence<Entry<T>>) => Map<T>} */
71
+ const fromEntries = seq.fold(map => entry => map.set(entry))(empty)
72
+
69
73
  module.exports = {
70
74
  /** @readonly */
71
75
  empty,
76
+ /** @readonly */
77
+ fromEntries,
72
78
  }
package/map/test.js CHANGED
@@ -1,5 +1,5 @@
1
1
  const { empty } = require('.')
2
- const list = require('../sequence/list')
2
+ const list = require('../sequence')
3
3
 
4
4
  {
5
5
  let m = empty.set('a')(1)
@@ -3,7 +3,7 @@ const { pipe } = require('../function')
3
3
  const option = require('../option')
4
4
  const { head, last, splitLast, splitFirst } = array
5
5
  const iter = require('../sequence/iterable')
6
- const seq = require('../sequence')
6
+ const seq = require('../sequence/operator')
7
7
 
8
8
  /**
9
9
  * @template T
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "functionalscript",
3
- "version": "0.0.185",
3
+ "version": "0.0.191",
4
4
  "description": "FunctionalScript is a functional subset of JavaScript",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -1,5 +1,5 @@
1
1
  const { pipe } = require('../../function')
2
- const seq = require('..')
2
+ const seq = require('../operator')
3
3
 
4
4
  /**
5
5
  * @template T
package/sequence/index.js CHANGED
@@ -1,92 +1,344 @@
1
+ const array = require('./array')
2
+ const seqOp = require('./operator')
3
+ const { pipe } = require('../function')
1
4
  const op = require('../function/operator')
5
+ const { logicalNot, strictEqual } = require('../function/operator')
2
6
 
3
7
  /**
4
- * @template T0
5
- * @template T1
6
- * @typedef {import('./array').Tuple2<T0, T1>} Tuple2
8
+ * @template T
9
+ * @typedef {() => Result<T>} SequenceFn
7
10
  */
8
11
 
9
12
  /**
10
13
  * @template T
11
- * @template R
12
- * @typedef {Tuple2<R, Scan<T, R>>} ScanResult
14
+ * @typedef {readonly [Sequence<T>, Sequence<T>]} Concat
13
15
  */
14
16
 
15
17
  /**
18
+ * Use `next` function to get `first` and `tail` of the list.
19
+ *
20
+ * Please note that the sequence also contains `Concat<T>. We need this as
21
+ * a workaround because modern JavaScript implementations don't support
22
+ * ES6 TCO (Tail Call Optimization). Without this wotkaround we may have
23
+ * a stack overflow if a list contains a lot of concateneted lists.
24
+ *
16
25
  * @template T
17
- * @template R
18
- * @typedef {(value: T) => ScanResult<T, R>} Scan
26
+ * @typedef { SequenceFn<T> | Concat<T>} Sequence
19
27
  */
20
28
 
21
29
  /**
22
30
  * @template T
23
- * @template R
24
- * @typedef {Tuple2<R, Scan<T, R>>} ExclusiveScan
31
+ * @typedef {FirstAndTail<T>|undefined} Result<T>
25
32
  */
26
33
 
27
- /** @type {<R, T>(operator: op.ReduceOperator<R, T>) => (prior: R) => Scan<T, R>} */
28
- const scan = operator => {
29
- /** @typedef {typeof operator extends op.ReduceOperator<infer R, infer T> ? [R, T] : never} RT */
30
- /** @typedef {RT[0]} R */
31
- /** @typedef {RT[1]} T */
32
- /** @type {(prior: R) => Scan<T, R>} */
33
- const f = prior => value => {
34
- const result = operator(prior)(value)
35
- return [result, f(result)]
36
- }
37
- return f
38
- }
39
-
40
- /** @type {<R, T>(operator: op.ReduceOperator<R, T>) => (first: R) => ExclusiveScan<T, R>} */
41
- const exclusiveScan = operator => first => [first, scan(operator)(first)]
42
-
43
- /**
34
+ /**
44
35
  * @template T
45
- * @typedef {Tuple2<number, T>} Entry
36
+ * @typedef {array.Tuple2<T, Sequence<T>>} FirstAndTail
46
37
  */
47
38
 
48
- /** @type {(index: number) => <T>(value: T) => ScanResult<T, Entry<T>>} */
49
- const createEntries = index => value => [[index, value], createEntries(index + 1)]
50
-
51
- const entries = createEntries(0)
39
+ const empty = () => undefined
52
40
 
53
- /** @type {(separator: string) => ExclusiveScan<string, string>} */
54
- const join = separator => ['', value => [value, scan(op.join(separator))(value)]]
41
+ /** @type {<F, T>(a: readonly[F, Sequence<T>]) => (b: Sequence<T>) => readonly[F, Sequence<T>]} */
42
+ const norm = ([a0, a1]) => b => [a0, [a1, b]]
55
43
 
56
- const sum = exclusiveScan(op.addition)(0)
44
+ /** @type {<T>(input: Sequence<T>) => Result<T>} */
45
+ const next = input => {
46
+ let i = input
47
+ while (true) {
48
+ if (typeof i === 'function') { return i() }
49
+ const [a, b] = i
50
+ if (typeof a === 'function') {
51
+ const result = a()
52
+ if (result !== undefined) {
53
+ return norm(result)(b)
54
+ }
55
+ i = b
56
+ } else {
57
+ i = norm(a)(b)
58
+ }
59
+ }
60
+ }
57
61
 
58
- /** @type {(a: number) => () => number} */
59
- const counter = a => () => a + 1
62
+ /** @type {<T>(input: Sequence<T>) => T|undefined} */
63
+ const first = input => {
64
+ const result = next(input)
65
+ if (result === undefined) { return undefined }
66
+ return result[0]
67
+ }
60
68
 
61
- const length = exclusiveScan(counter)(0)
69
+ /**
70
+ * @template T
71
+ * @template R
72
+ * @typedef {(list: Sequence<T>) => Sequence<R>} SequenceMap
73
+ */
62
74
 
63
75
  /**
64
76
  * @template T
65
77
  * @template R
66
- * @typedef {(value: T) => R} Func
78
+ * @typedef {(list: Sequence<T>) => R} SequenceReduce
67
79
  */
68
80
 
69
- /** @type {<T, R, X>(flatMap: (f: Func<T, readonly[R]>) => X) => (f: Func<T, R>) =>X} */
70
- const map = flatMap => f => flatMap(x => [f(x)])
81
+ /** @type {<T>(...array: readonly T[]) => Sequence<T>} */
82
+ const list = (...array) => {
83
+ /** @typedef {typeof array extends readonly(infer T)[] ? T : never} T */
84
+ let i = array.length
85
+ /** @type {Sequence<T>} */
86
+ let tail = empty
87
+ while (true) {
88
+ if (i === 0) { return tail }
89
+ i = i - 1
90
+ /** @type {FirstAndTail<T>} */
91
+ const result = [array[i], tail]
92
+ tail = () => result
93
+ }
94
+ }
95
+
96
+ /** @type {<T>(array: array.Array<T>) => Sequence<T>} */
97
+ const fromArray = a => {
98
+ /** @typedef {typeof a extends array.Array<infer T> ? T : never} T */
99
+ /** @type {(index: number) => Sequence<T>} */
100
+ const at = index => () => {
101
+ const result = array.at(index)(a)
102
+ if (result === undefined) { return undefined }
103
+ return [result[0], at(index + 1)]
104
+ }
105
+ return at(0)
106
+ }
107
+
108
+ /** @type {<T>(...array: readonly Sequence<T>[]) => Sequence<T>} */
109
+ const concat = (...array) => {
110
+ let i = array.length
111
+ if (i == 0) { return empty }
112
+ i = i - 1
113
+ let tail = array[i]
114
+ while (true) {
115
+ if (i === 0) { return tail }
116
+ i = i - 1
117
+ tail = [array[i], tail]
118
+ }
119
+ }
120
+
121
+ /** @type {(_: number) => Sequence<number>} */
122
+ const generate = n => {
123
+ /** @type {(_: number) => Sequence<number>} */
124
+ const f = i => () => {
125
+ if (n <= i) { return undefined }
126
+ return [i, f(i + 1)]
127
+ }
128
+ return f(0)
129
+ }
130
+
131
+ /** @type {<T, R>(f: (value: T) => Sequence<R>) => SequenceMap<T, R>} */
132
+ const flatMap = f => input => () => {
133
+ let i = input
134
+ while (true) {
135
+ const result = next(i)
136
+ if (result === undefined) { return undefined }
137
+ const [first, tail] = result
138
+ const firstResult = next(f(first))
139
+ if (firstResult !== undefined) {
140
+ return norm(firstResult)(flatMap(f)(tail))
141
+ }
142
+ i = tail
143
+ }
144
+ }
145
+
146
+ /** @type {<T>(list: Sequence<Sequence<T>>) => Sequence<T>} */
147
+ const flat = flatMap(i => i)
148
+
149
+ /** @type {<T, R>(f: (value: T) => R) => SequenceMap<T, R>} */
150
+ const map = f => flatMap(i => list(f(i)))
151
+
152
+ /** @type {<T>(f: (value: T) => boolean) => SequenceMap<T, T>} */
153
+ const filter = f => flatMap(i => f(i) ? list(i) : empty)
154
+
155
+ /** @type {<T, R>(f: (value: T) => R|undefined) => (value: T) => Sequence<R>} */
156
+ const filterMapFunc = f => i => {
157
+ const result = f(i)
158
+ if (result === undefined) { return empty }
159
+ return list(result)
160
+ }
161
+
162
+ /** @type {<T, R>(f: (value: T) => R|undefined) => SequenceMap<T, R>} */
163
+ const filterMap = f => flatMap(filterMapFunc(f))
164
+
165
+ /** @type {<T, R>(s: seqOp.Scan<T, R>) => SequenceMap<T, R>} */
166
+ const scan = s => input => () => {
167
+ const result = next(input)
168
+ if (result === undefined) {
169
+ return result
170
+ }
171
+ const [first, tail] = result
172
+ const [newFirst, newS] = s(first)
173
+ return [newFirst, scan(newS)(tail)]
174
+ }
175
+
176
+ /** @type {<T, R>(s: seqOp.ExclusiveScan<T, R>) => SequenceMap<T, R>} */
177
+ const exclusiveScan = ([first, s]) => input => () => [first, scan(s)(input)]
178
+
179
+ /** @type {<T>(def: T) => (input: Sequence<T>) => T} */
180
+ const last = def => input => {
181
+ let r = def
182
+ let i = input
183
+ while (true) {
184
+ const result = next(i)
185
+ if (result === undefined) {
186
+ return r
187
+ }
188
+ r = result[0]
189
+ i = result[1]
190
+ }
191
+ }
192
+
193
+ /** @type {<T, R>(s: seqOp.ExclusiveScan<T, R>) => (input: Sequence<T>) => R} */
194
+ const reduce = ([first, s]) => input => last(first)(scan(s)(input))
195
+
196
+ /** @type {<T, R>(ro: op.ReduceOperator<R, T>) => (first: R) => (input: Sequence<T>) => R} */
197
+ const fold = ro => first => reduce(seqOp.exclusiveScan(ro)(first))
198
+
199
+ const entries = scan(seqOp.entries)
200
+
201
+ const sum = reduce(seqOp.sum)
202
+
203
+ const length = reduce(seqOp.length)
204
+
205
+ const join = pipe(seqOp.join)(reduce)
206
+
207
+ /** @type {<T>(f: (value: T) => boolean) => SequenceMap<T, T>} */
208
+ const takeWhile = f => input => () => {
209
+ const result = next(input)
210
+ if (result === undefined || !f(result[0])) { return undefined }
211
+ return result
212
+ }
213
+
214
+ /** @type {(n: number) => <T>(input: Sequence<T>) => Sequence<T>} */
215
+ const drop = n => input => () => {
216
+ let iN = n
217
+ let iInput = input
218
+ while (true) {
219
+ const result = next(iInput)
220
+ if (iN <= 0 || result === undefined) { return result }
221
+ iN = iN - 1
222
+ iInput = result[1]
223
+ }
224
+ }
225
+
226
+ /** @type {(n: number) => <T>(input: Sequence<T>) => T|undefined} */
227
+ const at = n => input => first(drop(n)(input))
228
+
229
+ /** @type {<T>(f: (value: T) => boolean) => SequenceReduce<T, T|undefined>} */
230
+ const find = f => input => first(filter(f)(input))
231
+
232
+ /** @type {<T>(f: (value: T) => boolean) => SequenceReduce<T, boolean>} */
233
+ const some = f => input => find(x => x)(map(f)(input)) !== undefined
71
234
 
72
- /** @type {<T, X>(flatMap: (f: Func<T, readonly[T]|[]>) => X) => (f: Func<T, boolean>) =>X} */
73
- const filter = flatMap => f => flatMap(x => f(x) ? [x] : [])
235
+ /** @type {<T>(value: T) => SequenceReduce<T, boolean>} */
236
+ const includes = value => some(strictEqual(value))
237
+
238
+ /** @type {<T>(f: (value: T) => boolean) => SequenceReduce<T, boolean>} */
239
+ const every = f => input => !some(pipe(f)(logicalNot))(input)
240
+
241
+ /** @type {<T>(list: Sequence<T>) => Iterable<T>} */
242
+ const iterable = list => ({
243
+ *[Symbol.iterator]() {
244
+ let i = list
245
+ while (true) {
246
+ const result = next(i)
247
+ if (result === undefined) { return }
248
+ yield result[0]
249
+ i = result[1]
250
+ }
251
+ }
252
+ })
253
+
254
+ /** @type {<T>(list: Sequence<T>) => AsyncIterable<T>} */
255
+ const asyncIterable = list => ({
256
+ async *[Symbol.asyncIterator]() {
257
+ let i = list
258
+ while (true) {
259
+ const result = next(i)
260
+ if (result === undefined) { return }
261
+ yield result[0]
262
+ i = result[1]
263
+ }
264
+ }
265
+ })
266
+
267
+ /** @type {<A>(a: Sequence<A>) => <B>(b: Sequence<B>) => Sequence<array.Tuple2<A, B>>} */
268
+ const zip = a => b => () => {
269
+ const resultA = next(a)
270
+ if (resultA === undefined) { return undefined }
271
+ const resultB = next(b)
272
+ if (resultB === undefined) { return undefined }
273
+ return [[resultA[0], resultB[0]], zip(resultA[1])(resultB[1])]
274
+ }
275
+
276
+ /** @type {<T>(list: Sequence<T>) => readonly T[]} */
277
+ const toArray = input => Array.from(iterable(input))
74
278
 
75
279
  module.exports = {
76
280
  /** @readonly */
77
- exclusiveScan,
281
+ next,
282
+ /** @readonly */
283
+ list,
284
+ /** @readonly */
285
+ empty,
286
+ /** @readonly */
287
+ at,
288
+ /** @readonly */
289
+ concat,
290
+ /** @readonly */
291
+ generate,
292
+ /** @readonly */
293
+ first,
294
+ /** @readonly */
295
+ fromArray,
296
+ /** @readonly */
297
+ toArray,
298
+ /** @readonly */
299
+ iterable,
300
+ /** @readonly */
301
+ asyncIterable,
302
+ /** @readonly */
303
+ flatMap,
304
+ /** @readonly */
305
+ flat,
306
+ /** @readonly */
307
+ map,
308
+ /** @readonly */
309
+ filter,
310
+ /** @readonly */
311
+ filterMap,
78
312
  /** @readonly */
79
313
  scan,
80
314
  /** @readonly */
81
- join,
315
+ exclusiveScan,
316
+ /** @readonly */
317
+ last,
318
+ /** @readonly */
319
+ fold,
320
+ /** @readonly */
321
+ reduce,
322
+ /** @readonly */
323
+ entries,
82
324
  /** @readonly */
83
325
  sum,
84
326
  /** @readonly */
327
+ join,
328
+ /** @readonly */
85
329
  length,
86
330
  /** @readonly */
87
- entries,
331
+ drop,
88
332
  /** @readonly */
89
- map,
333
+ find,
90
334
  /** @readonly */
91
- filter,
92
- }
335
+ takeWhile,
336
+ /** @readonly */
337
+ some,
338
+ /** @readonly */
339
+ every,
340
+ /** @readonly */
341
+ includes,
342
+ /** @readonly */
343
+ zip,
344
+ }
@@ -1,5 +1,5 @@
1
1
  const { pipe } = require('../../function')
2
- const seq = require('..')
2
+ const seq = require('../operator')
3
3
 
4
4
  /** @type {<T>(a: Iterable<T>) => (b: Iterable<T>) => Iterable<T>} */
5
5
  const concat = a => b => ({
@@ -0,0 +1,92 @@
1
+ const op = require('../../function/operator')
2
+
3
+ /**
4
+ * @template T0
5
+ * @template T1
6
+ * @typedef {import('../array').Tuple2<T0, T1>} Tuple2
7
+ */
8
+
9
+ /**
10
+ * @template T
11
+ * @template R
12
+ * @typedef {Tuple2<R, Scan<T, R>>} ScanResult
13
+ */
14
+
15
+ /**
16
+ * @template T
17
+ * @template R
18
+ * @typedef {(value: T) => ScanResult<T, R>} Scan
19
+ */
20
+
21
+ /**
22
+ * @template T
23
+ * @template R
24
+ * @typedef {Tuple2<R, Scan<T, R>>} ExclusiveScan
25
+ */
26
+
27
+ /** @type {<R, T>(operator: op.ReduceOperator<R, T>) => (prior: R) => Scan<T, R>} */
28
+ const scan = operator => {
29
+ /** @typedef {typeof operator extends op.ReduceOperator<infer R, infer T> ? [R, T] : never} RT */
30
+ /** @typedef {RT[0]} R */
31
+ /** @typedef {RT[1]} T */
32
+ /** @type {(prior: R) => Scan<T, R>} */
33
+ const f = prior => value => {
34
+ const result = operator(prior)(value)
35
+ return [result, f(result)]
36
+ }
37
+ return f
38
+ }
39
+
40
+ /** @type {<R, T>(operator: op.ReduceOperator<R, T>) => (first: R) => ExclusiveScan<T, R>} */
41
+ const exclusiveScan = operator => first => [first, scan(operator)(first)]
42
+
43
+ /**
44
+ * @template T
45
+ * @typedef {Tuple2<number, T>} Entry
46
+ */
47
+
48
+ /** @type {(index: number) => <T>(value: T) => ScanResult<T, Entry<T>>} */
49
+ const createEntries = index => value => [[index, value], createEntries(index + 1)]
50
+
51
+ const entries = createEntries(0)
52
+
53
+ /** @type {(separator: string) => ExclusiveScan<string, string>} */
54
+ const join = separator => ['', value => [value, scan(op.join(separator))(value)]]
55
+
56
+ const sum = exclusiveScan(op.addition)(0)
57
+
58
+ /** @type {(a: number) => () => number} */
59
+ const counter = a => () => a + 1
60
+
61
+ const length = exclusiveScan(counter)(0)
62
+
63
+ /**
64
+ * @template T
65
+ * @template R
66
+ * @typedef {(value: T) => R} Func
67
+ */
68
+
69
+ /** @type {<T, R, X>(flatMap: (f: Func<T, readonly[R]>) => X) => (f: Func<T, R>) =>X} */
70
+ const map = flatMap => f => flatMap(x => [f(x)])
71
+
72
+ /** @type {<T, X>(flatMap: (f: Func<T, readonly[T]|[]>) => X) => (f: Func<T, boolean>) =>X} */
73
+ const filter = flatMap => f => flatMap(x => f(x) ? [x] : [])
74
+
75
+ module.exports = {
76
+ /** @readonly */
77
+ exclusiveScan,
78
+ /** @readonly */
79
+ scan,
80
+ /** @readonly */
81
+ join,
82
+ /** @readonly */
83
+ sum,
84
+ /** @readonly */
85
+ length,
86
+ /** @readonly */
87
+ entries,
88
+ /** @readonly */
89
+ map,
90
+ /** @readonly */
91
+ filter,
92
+ }
@@ -0,0 +1,62 @@
1
+ const seq = require('.')
2
+ const { sum } = require('./operator')
3
+ const op = require('./operator')
4
+
5
+ /** @type {<T>(input: seq.Sequence<T>) => void} */
6
+ const print = input => {
7
+ let i = input
8
+ while (true) {
9
+ const result = seq.next(i)
10
+ if (result === undefined) { return }
11
+ console.log(result[0])
12
+ i = result[1]
13
+ }
14
+ }
15
+
16
+ {
17
+ const big = seq.fromArray([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 42, 60])
18
+ const list0 = seq.fromArray([0, 1, 2, 3])
19
+ const list1 = seq.flatMap(x => seq.fromArray([x, x * 2, x * 3]))(list0)
20
+ const list2 = seq.concat(list0, list0)
21
+ const list3 = seq.exclusiveScan(sum)(list0)
22
+ const r = seq.find(x => x === 42)(big)
23
+ if (seq.every(x => x > 0)(big) !== true) { throw 'x'}
24
+ if (seq.every(x => x < 20)(big) !== false) { throw 'x' }
25
+ if (seq.some(x => x > 100)(big) !== false) { throw 'x' }
26
+ if (seq.some(x => x > 50)(big) !== true) { throw 'x' }
27
+ if (seq.first(seq.drop(16)(big)) !== 42) { throw 'drop'}
28
+ {
29
+ const a = seq.toArray(seq.generate(1_000_000))
30
+ let x = seq.concat(seq.fromArray(a), big)
31
+ const r = seq.next(x)
32
+ // print(x)
33
+ }
34
+ {
35
+ const a = seq.map(seq.generate)(seq.generate(100_000))
36
+ const array = seq.toArray(a)
37
+ const x = seq.concat(...array)
38
+ const r = seq.next(x)
39
+ // print(x)
40
+ }
41
+ {
42
+ let x = big
43
+ for (let i = 0; i < 1_000_000; ++i) {
44
+ x = seq.concat(seq.empty, x)
45
+ }
46
+ const r = seq.next(x)
47
+ // print(x)
48
+ }
49
+ {
50
+ let x = big
51
+ for (let i = 0; i < 1_000_000; ++i) {
52
+ x = seq.concat(x, seq.list(i))
53
+ }
54
+ const r = seq.next(x)
55
+ // print(x)
56
+ }
57
+ }
58
+
59
+ {
60
+ const x = seq.join(':')(seq.fromArray(["1", "2", "3", "4", "5", "6"]))
61
+ if (x !== "1:2:3:4:5:6") { throw x }
62
+ }
package/test.js CHANGED
@@ -1,10 +1,11 @@
1
1
  const i = require('./')
2
2
 
3
- require('./sequence/list/test')
3
+ require('./sequence/test')
4
4
  require('./btree/test')
5
5
  require('./sequence/iterable/test')
6
6
  require('./sequence/asyncIterable/test')
7
7
  require('./module-manager/test')
8
+ require('./json/test')
8
9
 
9
10
  /** @type {() => never} */
10
11
  const assert = () => { throw 'assert' }
@@ -1,305 +0,0 @@
1
- const array = require('../array')
2
- const base = require('..')
3
- const { pipe } = require('../../function')
4
- const { logicalNot, strictEqual } = require('../../function/operator')
5
-
6
- /**
7
- * @template 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
26
- */
27
-
28
- /**
29
- * @template T
30
- * @typedef {FirstAndTail<T>|undefined} Result<T>
31
- */
32
-
33
- /**
34
- * @template T
35
- * @typedef {array.Tuple2<T, List<T>>} FirstAndTail
36
- */
37
-
38
- const empty = () => undefined
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
-
68
- /**
69
- * @template T
70
- * @template R
71
- * @typedef {(list: List<T>) => List<R>} ListMap
72
- */
73
-
74
- /**
75
- * @template T
76
- * @template R
77
- * @typedef {(list: List<T>) => R} ListReduce
78
- */
79
-
80
- /** @type {<T>(first: T) => List<T>} */
81
- const one = first => () => [first, empty]
82
-
83
- /** @type {<T>(array: array.Array<T>) => List<T>} */
84
- const fromArray = a => {
85
- /** @typedef {typeof a extends array.Array<infer T> ? T : never} T */
86
- /** @type {(index: number) => List<T>} */
87
- const at = index => () => {
88
- const result = array.at(index)(a)
89
- if (result === undefined) { return undefined }
90
- return [result[0], at(index + 1)]
91
- }
92
- return at(0)
93
- }
94
-
95
- /** @type {<T>(list0: List<T>) => ListMap<T, T>} */
96
- const concat = a => b => [a, b]
97
-
98
- /** @type {<T, R>(f: (value: T) => List<R>) => ListMap<T, R>} */
99
- const flatMap = f => input => () => {
100
- let i = input
101
- while (true) {
102
- const result = next(i)
103
- if (result === undefined) { return undefined }
104
- const [first, tail] = result
105
- const firstResult = next(f(first))
106
- if (firstResult !== undefined) {
107
- const [firstFirst, firstTail] = firstResult
108
- return [firstFirst, concat(firstTail)(flatMap(f)(tail))]
109
- }
110
- i = tail
111
- }
112
- }
113
-
114
- /** @type {<T>(list: List<List<T>>) => List<T>} */
115
- const flat = flatMap(i => i)
116
-
117
- /** @type {<T, R>(f: (value: T) => R) => ListMap<T, R>} */
118
- const map = f => flatMap(i => one(f(i)))
119
-
120
- /** @type {<T>(f: (value: T) => boolean) => ListMap<T, T>} */
121
- const filter = f => flatMap(i => f(i) ? one(i) : empty)
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
-
133
- /** @type {<T, R>(s: base.Scan<T, R>) => ListMap<T, R>} */
134
- const scan = s => input => () => {
135
- const result = next(input)
136
- if (result === undefined) {
137
- return result
138
- }
139
- const [first, tail] = result
140
- const [newFirst, newS] = s(first)
141
- return [newFirst, scan(newS)(tail)]
142
- }
143
-
144
- /** @type {<T, R>(s: base.ExclusiveScan<T, R>) => ListMap<T, R>} */
145
- const exclusiveScan = ([first, s]) => input => () => [first, scan(s)(input)]
146
-
147
- /** @type {<T>(def: T) => (input: List<T>) => T} */
148
- const last = def => input => {
149
- let r = def
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]
158
- }
159
- }
160
-
161
- /** @type {<T, R>(s: base.ExclusiveScan<T, R>) => (input: List<T>) => R} */
162
- const reduce = ([first, s]) => input => last(first)(scan(s)(input))
163
-
164
- const entries = scan(base.entries)
165
-
166
- const sum = reduce(base.sum)
167
-
168
- const length = reduce(base.length)
169
-
170
- const join = pipe(base.join)(reduce)
171
-
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
177
- }
178
-
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>} */
207
- const iterable = list => ({
208
- *[Symbol.iterator]() {
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 }
226
- yield result[0]
227
- i = result[1]
228
- }
229
- }
230
- })
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
-
244
- module.exports = {
245
- /** @readonly */
246
- next,
247
- /** @readonly */
248
- one,
249
- /** @readonly */
250
- empty,
251
- /** @readonly */
252
- at,
253
- /** @readonly */
254
- concat,
255
- /** @readonly */
256
- first,
257
- /** @readonly */
258
- fromArray,
259
- /** @readonly */
260
- toArray,
261
- /** @readonly */
262
- iterable,
263
- /** @readonly */
264
- asyncIterable,
265
- /** @readonly */
266
- flatMap,
267
- /** @readonly */
268
- flat,
269
- /** @readonly */
270
- map,
271
- /** @readonly */
272
- filter,
273
- /** @readonly */
274
- filterMap,
275
- /** @readonly */
276
- scan,
277
- /** @readonly */
278
- exclusiveScan,
279
- /** @readonly */
280
- last,
281
- /** @readonly */
282
- reduce,
283
- /** @readonly */
284
- entries,
285
- /** @readonly */
286
- sum,
287
- /** @readonly */
288
- join,
289
- /** @readonly */
290
- length,
291
- /** @readonly */
292
- drop,
293
- /** @readonly */
294
- find,
295
- /** @readonly */
296
- takeWhile,
297
- /** @readonly */
298
- some,
299
- /** @readonly */
300
- every,
301
- /** @readonly */
302
- includes,
303
- /** @readonly */
304
- zip,
305
- }
@@ -1,43 +0,0 @@
1
- const list = require('.')
2
- const { sum } = require('..')
3
-
4
- /** @type {<T>(l: list.List<T>) => void} */
5
- const print = a => {
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]
12
- }
13
- }
14
-
15
- {
16
- const big = list.fromArray([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 42, 60])
17
- const list0 = list.fromArray([0, 1, 2, 3])
18
- const list1 = list.flatMap(x => list.fromArray([x, x * 2, x * 3]))(list0)
19
- const list2 = list.concat(list0)(list0)
20
- const list3 = list.exclusiveScan(sum)(list0)
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'}
27
- {
28
- let x = big
29
- for (let i = 0; i < 1_000_000; ++i) {
30
- x = list.concat(list.empty)(x)
31
- }
32
- const r = list.next(x)
33
- // print(x)
34
- }
35
- {
36
- let x = big
37
- for (let i = 0; i < 1_000_000; ++i) {
38
- x = list.concat(x)(list.one(i))
39
- }
40
- const r = list.next(x)
41
- // print(x)
42
- }
43
- }