functionalscript 0.0.222 → 0.0.229

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "functionalscript",
3
- "version": "0.0.222",
3
+ "version": "0.0.229",
4
4
  "description": "FunctionalScript is a functional subset of JavaScript",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/sequence/index.js CHANGED
@@ -19,7 +19,7 @@ const op = require('../function/operator')
19
19
 
20
20
  /**
21
21
  * @template T
22
- * @typedef { readonly[Sequence<T>, Sequence<T>] } Concat<T>
22
+ * @typedef { readonly[Sequence<T>, Sequence<T>]} Concat<T>
23
23
  */
24
24
 
25
25
  /**
@@ -34,6 +34,12 @@ const op = require('../function/operator')
34
34
 
35
35
  const empty = () => undefined
36
36
 
37
+ /** @type {<T>(first: T) => (tail: Sequence<T>) => Sequence<T>} */
38
+ const create = first => tail => () => ({ first, tail })
39
+
40
+ /** @type {<T>(sequence: Sequence<T>) => Node<T>} */
41
+ const nodeOne = sequence => [empty, sequence]
42
+
37
43
  /** @type {<T>(array: readonly T[]) => Result<T>} */
38
44
  const fromArray = array => {
39
45
  /** @typedef {typeof array extends readonly(infer T)[] ? T : never} T */
@@ -48,27 +54,23 @@ const fromArray = array => {
48
54
  /** @type {<T>(sequence: Sequence<T>) => Node<T>} */
49
55
  const node = sequence => sequence instanceof Array ? fromArray(sequence) : sequence()
50
56
 
51
- /** @type {<T>(concat: Concat<T>) => Sequence<T>} */
52
- const concatNext = ([a, b]) => {
53
- const result = node(a)
54
- if (result === undefined) {
55
- return b
56
- } else if (result instanceof Array) {
57
- const [aa, ab] = result
58
- return () => [aa, () => [ab, b]]
59
- } else {
60
- const { first, tail } = result
61
- return () => ({ first, tail: () => [tail, b] })
62
- }
63
- }
64
-
65
57
  /** @type {<T>(sequence: Sequence<T>) => Result<T>} */
66
58
  const next = sequence => {
67
59
  let i = sequence
68
60
  while (true) {
69
61
  const n = node(i)
70
62
  if (!(n instanceof Array)) { return n }
71
- i = concatNext(n)
63
+ const [a, b] = n
64
+ const result = node(a)
65
+ if (result === undefined) {
66
+ i = b
67
+ } else if (result instanceof Array) {
68
+ const [aa, ab] = result
69
+ i = () => [aa, () => [ab, b]]
70
+ } else {
71
+ const { first, tail } = result
72
+ return { first, tail: () => [tail, b] }
73
+ }
72
74
  }
73
75
  }
74
76
 
@@ -121,7 +123,7 @@ const flatMap = f => compose(map(f))(flat)
121
123
  /** @type {<T>(f: (value: T) => boolean) => (result: ResultOne<T>) => Node<T>} */
122
124
  const filterFn = f => ({ first, tail }) => {
123
125
  const fTail = filter(f)(tail)
124
- return f(first) ? { first, tail: fTail } : fTail()
126
+ return f(first) ? { first, tail: fTail } : nodeOne(fTail)
125
127
  }
126
128
 
127
129
  /** @type {<T>(f: (value: T) => boolean) => (input: Sequence<T>) => Thunk<T>} */
@@ -131,32 +133,26 @@ const filter = f => nextMap(filterFn(f))
131
133
  const filterMapFn = f => ({first, tail}) => {
132
134
  const fFirst = f(first)
133
135
  const fTail = filterMap(f)(tail)
134
- return fFirst === undefined ? fTail() : { first: fFirst, tail: fTail }
136
+ return fFirst === undefined ? nodeOne(fTail) : { first: fFirst, tail: fTail }
135
137
  }
136
138
 
137
139
  /** @type {<I, O>(f: (value: I) => O|undefined) => (input: Sequence<I>) => Thunk<O>} */
138
140
  const filterMap = f => nextMap(filterMapFn(f))
139
141
 
142
+ /** @type {<T>(f: (value: T) => boolean) => (result: ResultOne<T>) => Node<T>} */
143
+ const takeWhileFn = f => ({ first, tail }) => f(first) ? { first, tail: takeWhile(f)(tail) } :undefined
144
+
140
145
  /** @type {<T>(f: (value: T) => boolean) => (input: Sequence<T>) => Thunk<T>} */
141
- const takeWhile = f => input => () => {
142
- const result = next(input)
143
- if (result === undefined) { return undefined }
146
+ const takeWhile = f => nextMap(takeWhileFn(f))
147
+
148
+ /** @type {<T>(f: (value: T) => boolean) => (result: ResultOne<T>) => Node<T>} */
149
+ const dropWhileFn = f => result => {
144
150
  const { first, tail } = result
145
- if (!f(first)) { return undefined }
146
- return { first, tail: takeWhile(f)(result.tail) }
151
+ return f(first) ? nodeOne(dropWhile(f)(tail)) : result
147
152
  }
148
153
 
149
154
  /** @type {<T>(f: (value: T) => boolean) => (input: Sequence<T>) => Thunk<T>} */
150
- const dropWhile = f => input => () => {
151
- let i = input
152
- while (true) {
153
- const result = next(i)
154
- if (result === undefined) { return undefined }
155
- const { first, tail } = result
156
- if (!f(first)) return result
157
- i = tail
158
- }
159
- }
155
+ const dropWhile = f => nextMap(dropWhileFn(f))
160
156
 
161
157
  /** @type {<D>(def: D) => <T>(input: Sequence<T>) => D|T} */
162
158
  const first = def => input => {
@@ -210,15 +206,15 @@ const countdown = count => () => {
210
206
  * @typedef {readonly[A, ScanFunc<T, A>]} ScanState
211
207
  */
212
208
 
213
- /** @type {<T,A>(operator: ScanFunc<T, A>) => (input: Sequence<T>) => Thunk<A>} */
214
- const scan = operator => input => () => {
215
- const result = next(input)
216
- if (result === undefined) { return undefined }
217
- const { first, tail } = result
218
- const r = operator(first)
219
- return { first: r[0], tail: scan(r[1])(tail) }
209
+ /** @type {<T,A>(operator: ScanFunc<T, A>) => (result: ResultOne<T>) => Node<A>} */
210
+ const scanFn = operator => ({first, tail}) => {
211
+ const [value, nextOperator] = operator(first)
212
+ return { first: value, tail: scan(nextOperator)(tail) }
220
213
  }
221
214
 
215
+ /** @type {<T,A>(operator: ScanFunc<T, A>) => (input: Sequence<T>) => Thunk<A>} */
216
+ const scan = operator => nextMap(scanFn(operator))
217
+
222
218
  /** @type {<T,A>(operator: ScanFunc<T, A>) => <D>(def: D)=> (input: Sequence<T>) => D|A} */
223
219
  const scanReduce = operator => def => input => last(def)(scan(operator)(input))
224
220
 
@@ -269,6 +265,12 @@ const entryOp = index => value => [[index, value], entryOp(index + 1)]
269
265
  /** @type {<T>(input: Sequence<T>) => Thunk<Entry<T>>} */
270
266
  const entries = scan(entryOp(0))
271
267
 
268
+ /** @type {<T>(prior: Sequence<T>) => (value: T) => Sequence<T>} */
269
+ const reverseOp = prior => value => create(value)(prior)
270
+
271
+ /** @type {<T>(input: Sequence<T>) => Sequence<T>} */
272
+ const reverse = reduce(reverseOp)(empty)
273
+
272
274
  module.exports = {
273
275
  /** @readonly */
274
276
  empty,
@@ -293,6 +295,8 @@ module.exports = {
293
295
  /** @readonly */
294
296
  filter,
295
297
  /** @readonly */
298
+ filterMap,
299
+ /** @readonly */
296
300
  find,
297
301
  /** @readonly */
298
302
  some,
@@ -323,5 +327,7 @@ module.exports = {
323
327
  /** @readonly */
324
328
  length,
325
329
  /** @readonly */
330
+ reverse,
331
+ /** @readonly */
326
332
  countdown,
327
333
  }
package/sequence/test.js CHANGED
@@ -92,9 +92,31 @@ const stringify = sequence => json.stringify(sort)(_.toArray(sequence))
92
92
  if (result !== '[[0,"hello"],[1,"world"]]') { throw result }
93
93
  }
94
94
 
95
+ {
96
+ const result = stringify(_.reverse([]))
97
+ if (result !== '[]') { throw result }
98
+ }
99
+
100
+ {
101
+ const result = stringify(_.reverse([1,2,3,4,5]))
102
+ if (result !== '[5,4,3,2,1]') { throw result }
103
+ }
104
+
95
105
  // stress tests
96
106
 
97
107
  const stress = () => {
108
+
109
+ {
110
+ // 100_000_000 is too much
111
+ const n = 50_000_000
112
+ const result = _.toArray(_.countdown(n))
113
+ if (result.length !== n) { throw result.length }
114
+ const len = _.length(_.filter(x => x > n)(result))
115
+ if (len !== 0) { throw len }
116
+ }
117
+
118
+ console.log('first')
119
+
98
120
  {
99
121
  // 200_000_000 is too much
100
122
  const n = 100_000_000
@@ -133,9 +155,31 @@ const stress = () => {
133
155
  }
134
156
  const a = _.next(sequence)
135
157
  }
158
+
159
+ console.log('filterMap')
160
+
161
+ {
162
+ // 100_000_000 is too much
163
+ const n = 50_000_000
164
+ const result = _.toArray(_.countdown(n))
165
+ if (result.length !== n) { throw result.length }
166
+ const len = _.length(_.filterMap(() => undefined)(result))
167
+ if (len !== 0) { throw len }
168
+ }
169
+
170
+ console.log('dropWhile')
171
+
172
+ {
173
+ // 50_000_000 is too much
174
+ const n = 20_000_000
175
+ const result = _.toArray(_.countdown(n))
176
+ if (result.length !== n) { throw result.length }
177
+ const len = _.length(_.dropWhile(() => true)(result))
178
+ if (len !== 0) { throw len }
179
+ }
136
180
  }
137
181
 
138
- stress()
182
+ // stress()
139
183
 
140
184
  module.exports = {
141
185