functionalscript 0.0.178 → 0.0.180

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