functionalscript 0.0.220 → 0.0.228

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.220",
3
+ "version": "0.0.228",
4
4
  "description": "FunctionalScript is a functional subset of JavaScript",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/sequence/index.js CHANGED
@@ -19,16 +19,24 @@ 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
  /**
26
26
  * @template T
27
- * @typedef { undefined | { readonly first: T, readonly tail: Sequence<T> } } Result
27
+ * @typedef { undefined | ResultOne<T> } Result
28
+ */
29
+
30
+ /**
31
+ * @template T
32
+ * @typedef {{ readonly first: T, readonly tail: Sequence<T> }} ResultOne
28
33
  */
29
34
 
30
35
  const empty = () => undefined
31
36
 
37
+ /** @type {<T>(sequence: Sequence<T>) => Node<T>} */
38
+ const nodeOne = sequence => [empty, sequence]
39
+
32
40
  /** @type {<T>(array: readonly T[]) => Result<T>} */
33
41
  const fromArray = array => {
34
42
  /** @typedef {typeof array extends readonly(infer T)[] ? T : never} T */
@@ -43,27 +51,23 @@ const fromArray = array => {
43
51
  /** @type {<T>(sequence: Sequence<T>) => Node<T>} */
44
52
  const node = sequence => sequence instanceof Array ? fromArray(sequence) : sequence()
45
53
 
46
- /** @type {<T>(concat: Concat<T>) => Sequence<T>} */
47
- const concatNext = ([a, b]) => {
48
- const result = node(a)
49
- if (result === undefined) {
50
- return b
51
- } else if (result instanceof Array) {
52
- const [aa, ab] = result
53
- return () => [aa, () => [ab, b]]
54
- } else {
55
- const { first, tail } = result
56
- return () => ({ first, tail: () => [tail, b] })
57
- }
58
- }
59
-
60
54
  /** @type {<T>(sequence: Sequence<T>) => Result<T>} */
61
55
  const next = sequence => {
62
56
  let i = sequence
63
57
  while (true) {
64
58
  const n = node(i)
65
59
  if (!(n instanceof Array)) { return n }
66
- i = concatNext(n)
60
+ const [a, b] = n
61
+ const result = node(a)
62
+ if (result === undefined) {
63
+ i = b
64
+ } else if (result instanceof Array) {
65
+ const [aa, ab] = result
66
+ i = () => [aa, () => [ab, b]]
67
+ } else {
68
+ const { first, tail } = result
69
+ return { first, tail: () => [tail, b] }
70
+ }
67
71
  }
68
72
  }
69
73
 
@@ -73,15 +77,11 @@ const iterable = sequence => ({
73
77
  let i = sequence
74
78
  while (true) {
75
79
  if (i instanceof Array) { return yield *i }
76
- const n = node(i)
80
+ const n = next(i)
77
81
  if (n === undefined) { return }
78
- if (n instanceof Array) {
79
- i = concatNext(n)
80
- } else {
81
- const { first, tail } = n
82
- yield first
83
- i = tail
84
- }
82
+ const { first, tail } = n
83
+ yield first
84
+ i = tail
85
85
  }
86
86
  }
87
87
  })
@@ -92,47 +92,50 @@ const toArray = sequence => {
92
92
  return Array.from(iterable(sequence))
93
93
  }
94
94
 
95
- /** @type {<T>(sequence: Sequence<Sequence<T>>) => Thunk<T>} */
96
- const flat = sequence => () => {
97
- const n = next(sequence)
95
+ /** @type {<I, O>(f: (result: ResultOne<I>) => Node<O>) => (input: Sequence<I>) => Thunk<O>} */
96
+ const nextMap = f => input => () => {
97
+ const n = next(input)
98
98
  if (n === undefined) { return undefined }
99
- const { first, tail } = n
100
- return [first, flat(tail)]
99
+ return f(n)
101
100
  }
102
101
 
102
+ /** @type {<T>(result: ResultOne<Sequence<T>>) => Node<T>} */
103
+ const flatFn = ({first, tail}) => [first, flat(tail)]
104
+
105
+ /** @type {<T>(sequence: Sequence<Sequence<T>>) => Thunk<T>} */
106
+ const flat = nextMap(flatFn)
107
+
103
108
  /** @type {<T>(...array: readonly Sequence<T>[]) => Thunk<T>} */
104
109
  const concat = (...array) => flat(array)
105
110
 
111
+ /** @type {<I, O>(f: (value: I) => O) => (result: ResultOne<I>) => Node<O>} */
112
+ const mapFn = f => ({ first, tail }) => ({ first: f(first), tail: map(f)(tail) })
113
+
106
114
  /** @type {<I, O>(f: (value: I) => O) => (input: Sequence<I>) => Thunk<O>} */
107
- const map = f => sequence => () => {
108
- const n = next(sequence)
109
- if (n === undefined) { return undefined }
110
- const { first, tail } = n
111
- return { first: f(first), tail: map(f)(tail) }
112
- }
115
+ const map = f => nextMap(mapFn(f))
113
116
 
114
117
  /** @type {<I, O>(f: (value: I) => Sequence<O>) => (input: Sequence<I>) => Thunk<O>} */
115
- const flatMap = f => sequence => flat(map(f)(sequence))
118
+ const flatMap = f => compose(map(f))(flat)
116
119
 
117
- /** @type {<T>(f: (value: T) => boolean) => (input: Sequence<T>) => Thunk<T>} */
118
- const filter = f => sequence => () => {
119
- const n = next(sequence)
120
- if (n === undefined) { return undefined }
121
- const { first, tail } = n
120
+ /** @type {<T>(f: (value: T) => boolean) => (result: ResultOne<T>) => Node<T>} */
121
+ const filterFn = f => ({ first, tail }) => {
122
122
  const fTail = filter(f)(tail)
123
- return f(first) ? { first, tail: fTail } : fTail()
123
+ return f(first) ? { first, tail: fTail } : nodeOne(fTail)
124
124
  }
125
125
 
126
- /** @type {<I, O>(f: (value: I) => O|undefined) => (input: Sequence<I>) => Thunk<O>} */
127
- const filterMap = f => sequence => () => {
128
- const n = next(sequence)
129
- if (n === undefined) { return undefined }
130
- const { first, tail } = n
126
+ /** @type {<T>(f: (value: T) => boolean) => (input: Sequence<T>) => Thunk<T>} */
127
+ const filter = f => nextMap(filterFn(f))
128
+
129
+ /** @type {<I, O>(f: (value: I) => O|undefined) => (result: ResultOne<I>) => Node<O>} */
130
+ const filterMapFn = f => ({first, tail}) => {
131
131
  const fFirst = f(first)
132
132
  const fTail = filterMap(f)(tail)
133
- return fFirst === undefined ? fTail() : { first: fFirst, tail: fTail }
133
+ return fFirst === undefined ? nodeOne(fTail) : { first: fFirst, tail: fTail }
134
134
  }
135
135
 
136
+ /** @type {<I, O>(f: (value: I) => O|undefined) => (input: Sequence<I>) => Thunk<O>} */
137
+ const filterMap = f => nextMap(filterMapFn(f))
138
+
136
139
  /** @type {<T>(f: (value: T) => boolean) => (input: Sequence<T>) => Thunk<T>} */
137
140
  const takeWhile = f => input => () => {
138
141
  const result = next(input)
@@ -144,14 +147,11 @@ const takeWhile = f => input => () => {
144
147
 
145
148
  /** @type {<T>(f: (value: T) => boolean) => (input: Sequence<T>) => Thunk<T>} */
146
149
  const dropWhile = f => input => () => {
147
- let i = input
148
- while (true) {
149
- const result = next(i)
150
- if (result === undefined) { return undefined }
151
- const { first, tail } = result
152
- if (!f(first)) return result
153
- i = tail
154
- }
150
+ const result = next(input)
151
+ if (result === undefined) { return undefined }
152
+ const { first, tail } = result
153
+ if (f(first)) { return nodeOne(dropWhile(f)(tail)) }
154
+ return result
155
155
  }
156
156
 
157
157
  /** @type {<D>(def: D) => <T>(input: Sequence<T>) => D|T} */
@@ -248,6 +248,12 @@ const sum = fold(addition)(0)
248
248
  /** @type {(separator: string) => (input: Sequence<string>) => string} */
249
249
  const join = separator => fold(op.join(separator))('')
250
250
 
251
+ /** @type {(a: number) => () => number} */
252
+ const counter = a => () => a + 1
253
+
254
+ /** @type {<T>(input: Sequence<T>) => number} */
255
+ const length = reduce(counter)(0)
256
+
251
257
  /**
252
258
  * @template T
253
259
  * @typedef {readonly[number, T]} Entry
@@ -283,6 +289,8 @@ module.exports = {
283
289
  /** @readonly */
284
290
  filter,
285
291
  /** @readonly */
292
+ filterMap,
293
+ /** @readonly */
286
294
  find,
287
295
  /** @readonly */
288
296
  some,
@@ -311,5 +319,7 @@ module.exports = {
311
319
  /** @readonly */
312
320
  entries,
313
321
  /** @readonly */
322
+ length,
323
+ /** @readonly */
314
324
  countdown,
315
325
  }
package/sequence/test.js CHANGED
@@ -95,6 +95,18 @@ const stringify = sequence => json.stringify(sort)(_.toArray(sequence))
95
95
  // stress tests
96
96
 
97
97
  const stress = () => {
98
+
99
+ {
100
+ // 100_000_000 is too much
101
+ const n = 50_000_000
102
+ const result = _.toArray(_.countdown(n))
103
+ if (result.length !== n) { throw result.length }
104
+ const len = _.length(_.filter(x => x > n)(result))
105
+ if (len !== 0) { throw len }
106
+ }
107
+
108
+ console.log('first')
109
+
98
110
  {
99
111
  // 200_000_000 is too much
100
112
  const n = 100_000_000
@@ -133,9 +145,31 @@ const stress = () => {
133
145
  }
134
146
  const a = _.next(sequence)
135
147
  }
148
+
149
+ console.log('filterMap')
150
+
151
+ {
152
+ // 100_000_000 is too much
153
+ const n = 50_000_000
154
+ const result = _.toArray(_.countdown(n))
155
+ if (result.length !== n) { throw result.length }
156
+ const len = _.length(_.filterMap(() => undefined)(result))
157
+ if (len !== 0) { throw len }
158
+ }
159
+
160
+ console.log('dropWhile')
161
+
162
+ {
163
+ // 50_000_000 is too much
164
+ const n = 20_000_000
165
+ const result = _.toArray(_.countdown(n))
166
+ if (result.length !== n) { throw result.length }
167
+ const len = _.length(_.dropWhile(() => true)(result))
168
+ if (len !== 0) { throw len }
169
+ }
136
170
  }
137
171
 
138
- //stress()
172
+ // stress()
139
173
 
140
174
  module.exports = {
141
175