functionalscript 0.0.174 → 0.0.181

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.174",
3
+ "version": "0.0.181",
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
@@ -2,10 +2,27 @@ const array = require('../array')
2
2
  const option = require('../../option')
3
3
  const base = require('..')
4
4
  const { pipe } = require('../../function')
5
+ const { todo } = require('../../dev')
5
6
 
6
7
  /**
7
8
  * @template T
8
- * @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
9
26
  */
10
27
 
11
28
  /**
@@ -20,48 +37,65 @@ const { pipe } = require('../../function')
20
37
 
21
38
  const empty = () => undefined
22
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 get = 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
+
23
61
  /**
24
62
  * @template T
25
63
  * @template R
26
64
  * @typedef {(list: List<T>) => List<R>} ListMap
27
65
  */
28
66
 
29
- /** @type {<T>(first: T) => ListMap<T, T>} */
30
- const list = first => tail => () => [first, tail]
31
-
32
67
  /** @type {<T>(first: T) => List<T>} */
33
- const one = first => list(first)(empty)
68
+ const one = first => () => [first, empty]
34
69
 
35
70
  /** @type {<T>(array: array.Array<T>) => List<T>} */
36
71
  const fromArray = a => {
37
72
  /** @typedef {typeof a extends array.Array<infer T> ? T : never} T */
38
73
  /** @type {(index: number) => List<T>} */
39
- const at = index => {
40
- /** @type {(value: readonly [T]) => Result<T>} */
41
- const result = ([value]) => list(value)(at(index + 1))()
42
- return () => option.map(result)(array.at(index)(a))
74
+ const at = index => () => {
75
+ const result = array.at(index)(a)
76
+ if (result === undefined) { return undefined }
77
+ return [result[0], at(index + 1)]
43
78
  }
44
79
  return at(0)
45
80
  }
46
81
 
47
82
  /** @type {<T>(list0: List<T>) => ListMap<T, T>} */
48
- const concat = a => b => () => {
49
- /** @typedef {typeof a extends List<infer T> ? T : never} T */
50
- /** @type {(firstAntTail: FirstAndTail<T>) => Result<T>} */
51
- const defined = ([first, tail]) => [first, concat(tail)(b)]
52
- return option.match(defined)(b)(a())
53
- }
83
+ const concat = a => b => [a, b]
54
84
 
55
85
  /** @type {<T, R>(f: (value: T) => List<R>) => ListMap<T, R>} */
56
- const flatMap = f => {
57
- /** @typedef {typeof f extends (value: infer T) => List<infer R> ? [T, R] : never} TR */
58
- /** @typedef {TR[0]} T */
59
- /** @typedef {TR[1]} R */
60
- /** @type {(firstAntTail: FirstAndTail<T>) => Result<R>} */
61
- const defined = ([first, tail]) => concat(f(first))(listMap(tail))()
62
- /** @type {(list: List<T>) => List<R>} */
63
- const listMap = list => () => option.map(defined)(list())
64
- return listMap
86
+ const flatMap = f => input => () => {
87
+ let i = input
88
+ while (true) {
89
+ const result = get(i)
90
+ if (result === undefined) { return undefined }
91
+ const [first, tail] = result
92
+ const firstResult = get(f(first))
93
+ if (firstResult !== undefined) {
94
+ const [firstFirst, firstTail] = firstResult
95
+ return [firstFirst, concat(firstTail)(flatMap(f)(tail))]
96
+ }
97
+ i = tail
98
+ }
65
99
  }
66
100
 
67
101
  /** @type {<T>(list: List<List<T>>) => List<T>} */
@@ -83,25 +117,29 @@ const scan = s => input => () => {
83
117
  const [newFirst, newS] = s(first)
84
118
  return [newFirst, scan(newS)(tail)]
85
119
  }
86
- return option.map(defined)(input())
120
+ return option.map(defined)(get(input))
87
121
  }
88
122
 
89
123
  /** @type {<T, R>(s: base.InclusiveScan<T, R>) => ListMap<T, R>} */
90
- const inclusiveScan = ([first, s]) => input => list(first)(scan(s)(input))
124
+ const inclusiveScan = ([first, s]) => input => () => [first, scan(s)(input)]
91
125
 
92
126
  /** @type {<T>(def: T) => (input: List<T>) => T} */
93
127
  const last = def => input => {
94
- let i = input()
95
128
  let r = def
96
- while (i !== undefined) {
97
- r = i[0]
98
- i = i[1]()
129
+ let i = input
130
+ while (true) {
131
+ const result = get(i)
132
+ if (result === undefined) {
133
+ return r
134
+ }
135
+ r = result[0]
136
+ i = result[1]
99
137
  }
100
138
  return r
101
139
  }
102
140
 
103
141
  /** @type {<T, R>(s: base.InclusiveScan<T, R>) => (input: List<T>) => R} */
104
- const reduce = s => input => last(s[0])(inclusiveScan(s)(input))
142
+ const reduce = ([first, s]) => input => last(first)(scan(s)(input))
105
143
 
106
144
  const entries = scan(base.entries)
107
145
 
@@ -111,12 +149,19 @@ const length = reduce(base.length)
111
149
 
112
150
  const join = pipe(base.join)(reduce)
113
151
 
152
+ /** @type {<T>(f: (value: T) => boolean) => ListMap<T, T>} */
153
+ const takeWhile = f => input => () => {
154
+ const result = get(input)
155
+ if (result === undefined || !f(result[0])) { return undefined }
156
+ return result
157
+ }
158
+
114
159
  /** @type {<T>(f: (value: T) => boolean) => (input: List<T>) => T|undefined} */
115
160
  const find = f => input => {
116
161
  /** @typedef {typeof f extends (value: infer T) => boolean ? T : never} T */
117
162
  /** @type {(result: FirstAndTail<T>) => T} */
118
163
  const defined = ([first]) => first
119
- return option.map(defined)(filter(f)(input)())
164
+ return option.map(defined)(get(filter(f)(input)))
120
165
  }
121
166
 
122
167
  /**
@@ -125,17 +170,19 @@ const find = f => input => {
125
170
  */
126
171
  const iterable = list => ({
127
172
  *[Symbol.iterator]() {
128
- let result = list()
129
- while (result !== undefined) {
173
+ let i = list
174
+ while (true) {
175
+ const result = get(i)
176
+ if (result === undefined) { return }
130
177
  yield result[0]
131
- result = result[1]()
178
+ i = result[1]
132
179
  }
133
180
  }
134
181
  })
135
182
 
136
183
  module.exports = {
137
184
  /** @readonly */
138
- list,
185
+ get,
139
186
  /** @readonly */
140
187
  one,
141
188
  /** @readonly */
@@ -3,22 +3,36 @@ 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
 
13
15
  {
14
16
  const big = list.fromArray([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 42, 60])
15
- print(big)
16
- /*
17
17
  const list0 = list.fromArray([0, 1, 2, 3])
18
18
  const list1 = list.flatMap(x => list.fromArray([x, x * 2, x * 3]))(list0)
19
19
  const list2 = list.concat(list0)(list0)
20
20
  const list3 = list.inclusiveScan(sum)(list0)
21
- print(list3)
22
- const r = list.find(x => x === 42)(list.fromArray([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 42, 60]))
23
- */
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.get(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.get(x)
36
+ // print(x)
37
+ }
24
38
  }