functionalscript 0.0.182 → 0.0.190

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