functionalscript 0.0.178 → 0.0.185

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 CHANGED
@@ -10,6 +10,9 @@ Try FunctionalScript [here](https://functionalscript.com/).
10
10
 
11
11
  Create a new FunctionalScript repository on GitHub [here](https://github.com/functionalscript/template/generate).
12
12
 
13
+ One of the main challenges is how to make a pure functional language when ES6 TCO is not supported by Chrome and Firefox.
14
+ A workaround for this problem is to use `let` for renaming objects.
15
+
13
16
  ## JSON
14
17
 
15
18
  ```js
package/btree/index.js CHANGED
@@ -358,7 +358,7 @@ const valuesList = node => () => {
358
358
  }
359
359
  }
360
360
  }
361
- return f()()
361
+ return list.next(f())
362
362
  }
363
363
 
364
364
  module.exports = {
package/btree/test.js CHANGED
@@ -1,6 +1,7 @@
1
1
  const btree = require('.')
2
2
  const { setVisitor, valuesList } = btree
3
3
  const { cmp } = require('../cmp')
4
+ const list = require('../sequence/list')
4
5
 
5
6
  /** @type {(node: btree.Node<string>) => (value: string) => btree.Node<string>} */
6
7
  const set = node => value => {
@@ -21,11 +22,11 @@ const test = () => {
21
22
  //
22
23
  {
23
24
  /** @type {import('../sequence/list').Result<string>} */
24
- let result = valuesList(node)()
25
+ let result = list.next(valuesList(node))
25
26
  while (result !== undefined) {
26
27
  const t = result[0]
27
28
  console.log(t)
28
- result = result[1]()
29
+ result = list.next(result[1])
29
30
  }
30
31
  }
31
32
  }
@@ -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/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/list")
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.List<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/list')
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
 
@@ -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.178",
3
+ "version": "0.0.185",
4
4
  "description": "FunctionalScript is a functional subset of JavaScript",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -12,7 +12,7 @@ Sequence types:
12
12
  See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array
13
13
 
14
14
  - `length: Sequence<infer T> => number`
15
- - `at: number => Sequence<infer T> = T`
15
+ - `at: number => Sequence<infer T> = T|undefined`
16
16
  - `concat: Sequence<infer T> => Sequence<T> => Sequence<T>`
17
17
  - `entries: Sequence<infer T> => Sequence<[number, T]>`
18
18
  - `every: (infer T => boolean) => Sequence<T> => boolean`
@@ -24,7 +24,6 @@ See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Obj
24
24
  - `includes: infer T => Sequence<T> => boolean`
25
25
  - `indexOf: infer T => Sequence<T> => number`
26
26
  - `join: string => Sequence<string> => string`
27
- - `keys: Sequence<T> => Sequence<string>`
28
27
  - `lastIndexOf: infer T => Sequence<T> => number`
29
28
  - `map: (infer T => infer R) => Sequence<T> => Sequence<R>`
30
29
  - `reduce: ...Scan<T, R> => Sequence<T> => R`
@@ -38,6 +37,7 @@ See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Obj
38
37
 
39
38
  ### Priority 3.
40
39
 
40
+ - `keys: Sequence<T> => Sequence<string>`
41
41
  - `values: Sequence<infer T> => Sequence<T>`
42
42
 
43
43
  ## Prohibited Array Operations
@@ -30,6 +30,13 @@ const option = require('../../option')
30
30
  * @typedef {readonly [T, T, T]} Array3
31
31
  */
32
32
 
33
+ /**
34
+ * @template T0
35
+ * @template T1
36
+ * @template T2
37
+ * @typedef {readonly [T0, T1, T2]} Tuple3
38
+ */
39
+
33
40
  /** @typedef {0|1|2} Index3 */
34
41
 
35
42
  /**
@@ -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,5 +1,4 @@
1
1
  const op = require('../function/operator')
2
- const { id } = require('../function')
3
2
 
4
3
  /**
5
4
  * @template T0
@@ -22,12 +21,12 @@ const { id } = require('../function')
22
21
  /**
23
22
  * @template T
24
23
  * @template R
25
- * @typedef {Tuple2<R, Scan<T, R>>} InclusiveScan
24
+ * @typedef {Tuple2<R, Scan<T, R>>} ExclusiveScan
26
25
  */
27
26
 
28
- /** @type {<R, T>(operator: op.BinaryOperator<R, T>) => (prior: R) => Scan<T, R>} */
27
+ /** @type {<R, T>(operator: op.ReduceOperator<R, T>) => (prior: R) => Scan<T, R>} */
29
28
  const scan = operator => {
30
- /** @typedef {typeof operator extends op.BinaryOperator<infer R, infer T> ? [R, T] : never} RT */
29
+ /** @typedef {typeof operator extends op.ReduceOperator<infer R, infer T> ? [R, T] : never} RT */
31
30
  /** @typedef {RT[0]} R */
32
31
  /** @typedef {RT[1]} T */
33
32
  /** @type {(prior: R) => Scan<T, R>} */
@@ -38,8 +37,8 @@ const scan = operator => {
38
37
  return f
39
38
  }
40
39
 
41
- /** @type {<R, T>(operator: op.BinaryOperator<R, T>) => (first: R) => InclusiveScan<T, R>} */
42
- const inclusiveScan = operator => first => [first, scan(operator)(first)]
40
+ /** @type {<R, T>(operator: op.ReduceOperator<R, T>) => (first: R) => ExclusiveScan<T, R>} */
41
+ const exclusiveScan = operator => first => [first, scan(operator)(first)]
43
42
 
44
43
  /**
45
44
  * @template T
@@ -51,12 +50,15 @@ const createEntries = index => value => [[index, value], createEntries(index + 1
51
50
 
52
51
  const entries = createEntries(0)
53
52
 
54
- /** @type {(separator: string) => InclusiveScan<string, string>} */
53
+ /** @type {(separator: string) => ExclusiveScan<string, string>} */
55
54
  const join = separator => ['', value => [value, scan(op.join(separator))(value)]]
56
55
 
57
- const sum = inclusiveScan(op.addition)(0)
56
+ const sum = exclusiveScan(op.addition)(0)
58
57
 
59
- const length = inclusiveScan(a => () => a + 1)(0)
58
+ /** @type {(a: number) => () => number} */
59
+ const counter = a => () => a + 1
60
+
61
+ const length = exclusiveScan(counter)(0)
60
62
 
61
63
  /**
62
64
  * @template T
@@ -72,7 +74,7 @@ const filter = flatMap => f => flatMap(x => f(x) ? [x] : [])
72
74
 
73
75
  module.exports = {
74
76
  /** @readonly */
75
- inclusiveScan,
77
+ exclusiveScan,
76
78
  /** @readonly */
77
79
  scan,
78
80
  /** @readonly */
@@ -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 */
@@ -1,12 +1,28 @@
1
1
  const array = require('../array')
2
- const option = require('../../option')
3
2
  const base = require('..')
4
3
  const { pipe } = require('../../function')
5
- const { todo } = require('../../dev')
4
+ const { logicalNot, strictEqual } = require('../../function/operator')
6
5
 
7
6
  /**
8
7
  * @template T
9
- * @typedef {() => Result<T>} List
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
10
26
  */
11
27
 
12
28
  /**
@@ -21,60 +37,72 @@ const { todo } = require('../../dev')
21
37
 
22
38
  const empty = () => undefined
23
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
+
24
68
  /**
25
69
  * @template T
26
70
  * @template R
27
71
  * @typedef {(list: List<T>) => List<R>} ListMap
28
72
  */
29
73
 
30
- /** @type {<T>(first: T) => ListMap<T, T>} */
31
- const list = first => tail => () => [first, tail]
74
+ /**
75
+ * @template T
76
+ * @template R
77
+ * @typedef {(list: List<T>) => R} ListReduce
78
+ */
32
79
 
33
80
  /** @type {<T>(first: T) => List<T>} */
34
- const one = first => list(first)(empty)
81
+ const one = first => () => [first, empty]
35
82
 
36
83
  /** @type {<T>(array: array.Array<T>) => List<T>} */
37
84
  const fromArray = a => {
38
85
  /** @typedef {typeof a extends array.Array<infer T> ? T : never} T */
39
86
  /** @type {(index: number) => List<T>} */
40
- const at = index => {
41
- /** @type {(value: readonly [T]) => Result<T>} */
42
- const result = ([value]) => list(value)(at(index + 1))()
43
- return () => option.map(result)(array.at(index)(a))
87
+ const at = index => () => {
88
+ const result = array.at(index)(a)
89
+ if (result === undefined) { return undefined }
90
+ return [result[0], at(index + 1)]
44
91
  }
45
92
  return at(0)
46
93
  }
47
94
 
48
- /**
49
- * Note: the function is not completly lazy.
50
- * it calls `a()` as soon as `a` and `b` are provided.
51
- * Othrewise we may have a stack overflow if a list
52
- * contains a lot of concateneted empty lists.
53
- * And we can't relay on ES6 TCO (Tail Call Optimization)
54
- * because it's not supported by Chrome and Firefox.
55
- * @type {<T>(list0: List<T>) => ListMap<T, T>}
56
- */
57
- const concat = a => b => {
58
- const result = a()
59
- if (result !== undefined) {
60
- const [first, tail] = result
61
- return () => [first, concat(tail)(b)]
62
- }
63
- return b
64
- // /** @typedef {typeof a extends List<infer T> ? T : never} T */
65
- // /** @type {(firstAntTail: FirstAndTail<T>) => Result<T>} */
66
- // const defined = ([first, tail]) => [first, concat(tail)(b)]
67
- // return option.match(defined)(b)(a())
68
- }
95
+ /** @type {<T>(list0: List<T>) => ListMap<T, T>} */
96
+ const concat = a => b => [a, b]
69
97
 
70
98
  /** @type {<T, R>(f: (value: T) => List<R>) => ListMap<T, R>} */
71
99
  const flatMap = f => input => () => {
72
100
  let i = input
73
101
  while (true) {
74
- const result = i()
102
+ const result = next(i)
75
103
  if (result === undefined) { return undefined }
76
104
  const [first, tail] = result
77
- const firstResult = f(first)()
105
+ const firstResult = next(f(first))
78
106
  if (firstResult !== undefined) {
79
107
  const [firstFirst, firstTail] = firstResult
80
108
  return [firstFirst, concat(firstTail)(flatMap(f)(tail))]
@@ -92,35 +120,46 @@ const map = f => flatMap(i => one(f(i)))
92
120
  /** @type {<T>(f: (value: T) => boolean) => ListMap<T, T>} */
93
121
  const filter = f => flatMap(i => f(i) ? one(i) : empty)
94
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
+
95
133
  /** @type {<T, R>(s: base.Scan<T, R>) => ListMap<T, R>} */
96
134
  const scan = s => input => () => {
97
- /** @typedef {typeof s extends base.Scan<infer T, infer R> ? [T, R] : never} TR */
98
- /** @typedef {TR[0]} T */
99
- /** @typedef {TR[1]} R */
100
- /** @type {(firstAndTail: FirstAndTail<T>) => Result<R>} */
101
- const defined = ([first, tail]) => {
102
- const [newFirst, newS] = s(first)
103
- return [newFirst, scan(newS)(tail)]
135
+ const result = next(input)
136
+ if (result === undefined) {
137
+ return result
104
138
  }
105
- return option.map(defined)(input())
139
+ const [first, tail] = result
140
+ const [newFirst, newS] = s(first)
141
+ return [newFirst, scan(newS)(tail)]
106
142
  }
107
143
 
108
- /** @type {<T, R>(s: base.InclusiveScan<T, R>) => ListMap<T, R>} */
109
- const inclusiveScan = ([first, s]) => input => list(first)(scan(s)(input))
144
+ /** @type {<T, R>(s: base.ExclusiveScan<T, R>) => ListMap<T, R>} */
145
+ const exclusiveScan = ([first, s]) => input => () => [first, scan(s)(input)]
110
146
 
111
147
  /** @type {<T>(def: T) => (input: List<T>) => T} */
112
148
  const last = def => input => {
113
- let i = input()
114
149
  let r = def
115
- while (i !== undefined) {
116
- r = i[0]
117
- i = i[1]()
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]
118
158
  }
119
- return r
120
159
  }
121
160
 
122
- /** @type {<T, R>(s: base.InclusiveScan<T, R>) => (input: List<T>) => R} */
123
- const reduce = s => input => last(s[0])(inclusiveScan(s)(input))
161
+ /** @type {<T, R>(s: base.ExclusiveScan<T, R>) => (input: List<T>) => R} */
162
+ const reduce = ([first, s]) => input => last(first)(scan(s)(input))
124
163
 
125
164
  const entries = scan(base.entries)
126
165
 
@@ -130,42 +169,100 @@ const length = reduce(base.length)
130
169
 
131
170
  const join = pipe(base.join)(reduce)
132
171
 
133
- /** @type {<T>(f: (value: T) => boolean) => (input: List<T>) => T|undefined} */
134
- const find = f => input => {
135
- /** @typedef {typeof f extends (value: infer T) => boolean ? T : never} T */
136
- /** @type {(result: FirstAndTail<T>) => T} */
137
- const defined = ([first]) => first
138
- return option.map(defined)(filter(f)(input)())
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
139
177
  }
140
178
 
141
- /**
142
- * Note: probably, it's possible to implement using the `scan` concept.
143
- * @type {<T>(list: List<T>) => Iterable<T>}
144
- */
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>} */
145
207
  const iterable = list => ({
146
208
  *[Symbol.iterator]() {
147
- let result = list()
148
- while (result !== undefined) {
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 }
149
226
  yield result[0]
150
- result = result[1]()
227
+ i = result[1]
151
228
  }
152
229
  }
153
230
  })
154
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
+
155
244
  module.exports = {
156
245
  /** @readonly */
157
- list,
246
+ next,
158
247
  /** @readonly */
159
248
  one,
160
249
  /** @readonly */
161
250
  empty,
162
251
  /** @readonly */
252
+ at,
253
+ /** @readonly */
163
254
  concat,
164
255
  /** @readonly */
256
+ first,
257
+ /** @readonly */
165
258
  fromArray,
166
259
  /** @readonly */
260
+ toArray,
261
+ /** @readonly */
167
262
  iterable,
168
263
  /** @readonly */
264
+ asyncIterable,
265
+ /** @readonly */
169
266
  flatMap,
170
267
  /** @readonly */
171
268
  flat,
@@ -174,9 +271,11 @@ module.exports = {
174
271
  /** @readonly */
175
272
  filter,
176
273
  /** @readonly */
274
+ filterMap,
275
+ /** @readonly */
177
276
  scan,
178
277
  /** @readonly */
179
- inclusiveScan,
278
+ exclusiveScan,
180
279
  /** @readonly */
181
280
  last,
182
281
  /** @readonly */
@@ -190,5 +289,17 @@ module.exports = {
190
289
  /** @readonly */
191
290
  length,
192
291
  /** @readonly */
292
+ drop,
293
+ /** @readonly */
193
294
  find,
295
+ /** @readonly */
296
+ takeWhile,
297
+ /** @readonly */
298
+ some,
299
+ /** @readonly */
300
+ every,
301
+ /** @readonly */
302
+ includes,
303
+ /** @readonly */
304
+ zip,
194
305
  }
@@ -3,10 +3,12 @@ const { sum } = require('..')
3
3
 
4
4
  /** @type {<T>(l: list.List<T>) => void} */
5
5
  const print = a => {
6
- let i = a()
7
- while (i !== undefined) {
8
- console.log(i[0])
9
- i = i[1]()
6
+ let i = a
7
+ while (true) {
8
+ const result = list.next(i)
9
+ if (result === undefined) { return }
10
+ // console.log(result[0])
11
+ i = result[1]
10
12
  }
11
13
  }
12
14
 
@@ -15,22 +17,27 @@ const print = a => {
15
17
  const list0 = list.fromArray([0, 1, 2, 3])
16
18
  const list1 = list.flatMap(x => list.fromArray([x, x * 2, x * 3]))(list0)
17
19
  const list2 = list.concat(list0)(list0)
18
- const list3 = list.inclusiveScan(sum)(list0)
20
+ const list3 = list.exclusiveScan(sum)(list0)
19
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'}
20
27
  {
21
28
  let x = big
22
- for (let i = 0; i < 10000; ++i) {
29
+ for (let i = 0; i < 1_000_000; ++i) {
23
30
  x = list.concat(list.empty)(x)
24
31
  }
25
- const r = x()
26
- print(x)
32
+ const r = list.next(x)
33
+ // print(x)
27
34
  }
28
35
  {
29
36
  let x = big
30
- for (let i = 0; i < 10000; ++i) {
31
- x = list.concat(x)(list.empty)
37
+ for (let i = 0; i < 1_000_000; ++i) {
38
+ x = list.concat(x)(list.one(i))
32
39
  }
33
- const r = x()
34
- print(x)
40
+ const r = list.next(x)
41
+ // print(x)
35
42
  }
36
43
  }