functionalscript 0.0.238 → 0.0.242

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.
@@ -5,9 +5,7 @@ name: Node.js CI
5
5
 
6
6
  on:
7
7
  push:
8
- branches: [ main ]
9
8
  pull_request:
10
- branches: [ main ]
11
9
 
12
10
  jobs:
13
11
  build:
@@ -0,0 +1,55 @@
1
+ # Common.js
2
+
3
+ ```ts
4
+ // package/index.js
5
+
6
+ type PackageGet = (packageId: string) => Package | undefined
7
+ type Package = {
8
+ // returns a global package id.
9
+ readonly dependency: (localPackageId: string) => string | undefined
10
+ // returns source of the file.
11
+ readonly file: (localFileId: string) => string | undefined
12
+ }
13
+
14
+ // module/index.js
15
+
16
+ type ModuleMapInterface<M> = {
17
+ readonly at: (moduleId: string) => (moduleMap: M) => ModuleState | undefined
18
+ readonly insert: (moduleId: string) => (moduleState: ModuleState) => (moduleMap: M) => M
19
+ }
20
+
21
+ type ModuleState = readonly['ok', Module] | readonly['error', ModuleError] | readonly['building']
22
+
23
+ type Module = {
24
+ readonly exports: unknown
25
+ readonly requireMap: object.Map<string>
26
+ }
27
+
28
+ type ModuleError = 'file not found' | 'compile error' | 'runtime error' | 'circular reference'
29
+
30
+ type ModuleId = {
31
+ readonly packageId: string,
32
+ readonly path: readonly string[],
33
+ }
34
+
35
+ const moduleIdToString: (moduleId: ModuleId) => string;
36
+
37
+ // build/index.js
38
+
39
+ type BuildConfig<M> = {
40
+ readonly packageGet: PackageGet
41
+ readonly moduleMapInterface: ModuleMapInterface<M>
42
+ readonly moduleId: ModuleId
43
+ readonly moduleMap: M // mutable
44
+ }
45
+
46
+ type BuildState<M> = {
47
+ readonly packageGet: PackageGet
48
+ readonly moduleMapInterface: ModuleMapInterface<M>
49
+ readonly moduleId: ModuleId
50
+ readonly moduleMap: M // mutable
51
+ readonly ModuleRequireMap: map.Map<string> // mutable
52
+ }
53
+
54
+ const getOrBuild: <M>(buildConfig: BuildConfig<M>) => readonly[ModuleState, M];
55
+ ```
@@ -1,22 +1,35 @@
1
- const map = require('../../types/map')
2
1
  const object = require('../../types/object')
3
- const run = require('../run')
4
- const seq = require('../../types/sequence')
5
2
 
6
3
  /**
4
+ * @template M
7
5
  * @typedef {{
8
- * readonly map: object.Map<string>
9
- * readonly run: run.Module
10
- * }} Module
6
+ * readonly at: (moduleId: string) => (moduleMap: M) => ModuleState | undefined
7
+ * readonly insert: (moduleId: string) => (moduleState: ModuleState) => (moduleMap: M) => M
8
+ * }} ModuleMapInterface
11
9
  */
12
10
 
13
11
  /**
12
+ * @typedef {|
13
+ * readonly['ok', Module] |
14
+ * readonly['error', ModuleError] |
15
+ * readonly['building']
16
+ * } ModuleState
17
+ */
18
+
19
+ /**
14
20
  * @typedef {{
15
- * readonly map: map.Map<Module>
16
- * readonly order: seq.Sequence<string>
17
- * }} Cache
21
+ * readonly exports: unknown
22
+ * readonly requireMap: object.Map<string>
23
+ * }} Module
18
24
  */
19
25
 
20
- /** @typedef {(path: string) => string|undefined} ReadFile */
26
+ /**
27
+ * @typedef {|
28
+ * 'file not found' |
29
+ * 'compile error' |
30
+ * 'runtime error' |
31
+ * 'circular reference'
32
+ * } ModuleError
33
+ */
21
34
 
22
35
  module.exports = {}
@@ -1,5 +1,5 @@
1
1
  const json = require('../../../json')
2
- const seq = require('../../../types/sequence')
2
+ const seq = require('../../../types/list')
3
3
 
4
4
  /** @typedef {readonly[string, string]} DependencyJson */
5
5
 
@@ -1,7 +1,4 @@
1
1
  const _ = require('.')
2
- const json = require('../../../json')
3
- const { sort } = require('../../../types/object')
4
- const seq = require('../../../types/sequence')
5
2
 
6
3
  {
7
4
  if (!_.isDependenciesJson(undefined)) { throw 'error' }
@@ -20,9 +20,14 @@ const isPackageJson = j => {
20
20
  return true
21
21
  }
22
22
 
23
- /** @typedef {object.Map<string>} Files */
23
+ /**
24
+ * @typedef {{
25
+ * readonly dependency: (localPackageId: string) => string | undefined
26
+ * readonly file: (localFileId: string) => string | undefined
27
+ * }} Package
28
+ */
24
29
 
25
- /** @typedef {object.Map<dep.DependencyJson>} PackageMap */
30
+ /** @typedef {(packageId: string) => Package | undefined} PackageGet */
26
31
 
27
32
  module.exports = {
28
33
  /** @readonly */
@@ -1,9 +1,9 @@
1
- const seq = require("../../types/sequence")
1
+ const seq = require("../../types/list")
2
2
  const option = require("../../types/option")
3
3
  const { compose } = require("../../types/function")
4
4
  const dep = require("../package/dependencies")
5
5
  const { at } = require("../../types/object")
6
- const pack = require("../package")
6
+ // const pack = require("../package")
7
7
 
8
8
  /** @typedef {readonly string[]} Items */
9
9
 
@@ -18,7 +18,7 @@ const pack = require("../package")
18
18
  /** @type {(path: string) => readonly string[]} */
19
19
  const split = path => path.split('/')
20
20
 
21
- /** @type {(s: undefined|seq.Sequence<string>) => (items: string) => undefined|seq.Sequence<string>} */
21
+ /** @type {(s: undefined|seq.List<string>) => (items: string) => undefined|seq.List<string>} */
22
22
  const normItemsOp = prior => item => {
23
23
  if (prior === undefined) { return undefined }
24
24
  switch (item) {
@@ -29,17 +29,17 @@ const normItemsOp = prior => item => {
29
29
  return result.tail
30
30
  }
31
31
  default: {
32
- return seq.sequence(item)(prior)
32
+ return seq.nonEmpty(item)(prior)
33
33
  }
34
34
  }
35
35
  }
36
36
 
37
- /** @type {(items: seq.Sequence<string>) => seq.Sequence<string>|undefined} */
37
+ /** @type {(items: seq.List<string>) => seq.List<string>|undefined} */
38
38
  const normItems = compose(seq.reduce(normItemsOp)([]))(option.map(seq.reverse))
39
39
 
40
40
  /** @type {(local: string) => (path: string) => LocalPath|undefined} */
41
41
  const parseLocal = local => {
42
- /** @type {(path: string) => readonly[boolean, seq.Sequence<string>]} */
42
+ /** @type {(path: string) => readonly[boolean, seq.List<string>]} */
43
43
  const fSeq = path => {
44
44
  const pathSeq = split(path)
45
45
  switch (seq.first(undefined)(pathSeq)) {
@@ -61,9 +61,9 @@ const parseLocal = local => {
61
61
  return f
62
62
  }
63
63
 
64
- /** @typedef {readonly[string, seq.Sequence<string>]} IdPath */
64
+ /** @typedef {readonly[string, seq.List<string>]} IdPath */
65
65
 
66
- /** @type {(prior: readonly[string|undefined, seq.Sequence<string>]) => seq.Thunk<IdPath>} */
66
+ /** @type {(prior: readonly[string|undefined, seq.List<string>]) => seq.Thunk<IdPath>} */
67
67
  const variants = prior => () => {
68
68
  const [a, b] = prior
69
69
  const r = seq.next(b)
@@ -88,7 +88,7 @@ const mapDependency = d => ([external, internal]) => {
88
88
  * }} Path
89
89
  */
90
90
 
91
- /** @type {(d: dep.DependenciesJson) => (dir: boolean) => (items: seq.Sequence<string>) => Path|undefined} */
91
+ /** @type {(d: dep.DependenciesJson) => (dir: boolean) => (items: seq.List<string>) => Path|undefined} */
92
92
  const parseGlobal = d => dir => items => {
93
93
  if (d === undefined) { return undefined }
94
94
  const v = variants([undefined, items])
@@ -9,7 +9,7 @@ const result = require('../../types/result')
9
9
 
10
10
  /**
11
11
  * @template T
12
- * @typedef {(prior: T) => (path: string) => ModuleResult<T>} Require
12
+ * @typedef {(path: string) => (prior: T) => ModuleResult<T>} Require
13
13
  */
14
14
 
15
15
  /** @typedef {(source: string) => result.Result<Module, unknown>} Compile */
@@ -6,7 +6,7 @@ const run = require('../../commonjs/run')
6
6
  const build = f => immutableRequire => mutableData => {
7
7
  /** @type {(path: string) => unknown} */
8
8
  const mutableRequire = path => {
9
- const [result, data] = immutableRequire(mutableData)(path)
9
+ const [result, data] = immutableRequire(path)(mutableData)
10
10
  mutableData = data
11
11
  return unwrap(result)
12
12
  }
@@ -41,7 +41,7 @@ const run = require('../../commonjs/run')
41
41
  if (d[0] !== 'ok') { throw d }
42
42
 
43
43
  /** @type {run.Require<number>} */
44
- const req = prior => path => {
44
+ const req = path => prior => {
45
45
  if (path !== 'm') { throw path }
46
46
  return d[1](req)(prior + 1)
47
47
  }
@@ -1,7 +1,6 @@
1
1
  const cp = require('child_process')
2
2
  const fs = require('fs')
3
- const json = require('../../../json')
4
- const { isPackageJson } = require('../../../commonjs/package')
3
+ const package_json = require('../../../package.json')
5
4
 
6
5
  const b =cp.execSync('git log --oneline')
7
6
 
@@ -11,10 +10,6 @@ const v = `0.0.${r}`
11
10
 
12
11
  console.log(`version: ${v}`)
13
12
 
14
- const package_json = json.parse(fs.readFileSync('package.json').toString())
15
-
16
- if (!isPackageJson(package_json)) { throw 'error' }
17
-
18
13
  const x = { ...package_json, version: v }
19
14
 
20
15
  fs.writeFileSync('package.json', JSON.stringify(x, null, 2))
package/json/index.js CHANGED
@@ -1,7 +1,7 @@
1
- const seq = require('../types/sequence')
1
+ const seq = require('../types/list')
2
2
  const object = require('../types/object')
3
3
  const array = require('../types/array')
4
- const { todo } = require('../dev')
4
+ const op = require('../types/function/operator')
5
5
 
6
6
  /**
7
7
  * @typedef {{
@@ -13,9 +13,9 @@ const { todo } = require('../dev')
13
13
 
14
14
  /** @typedef {Object|boolean|string|number|null|Array} Unknown */
15
15
 
16
- /** @type {(value: Unknown) => (path: seq.Sequence<string>) => (src: Unknown|undefined) => Unknown} */
16
+ /** @type {(value: Unknown) => (path: seq.List<string>) => (src: Unknown|undefined) => Unknown} */
17
17
  const setProperty = value => {
18
- /** @type {(path: seq.Sequence<string>) => (src: Unknown|undefined) => Unknown} */
18
+ /** @type {(path: seq.List<string>) => (src: Unknown|undefined) => Unknown} */
19
19
  const f = path => src => {
20
20
  const result = seq.next(path)
21
21
  if (result === undefined) { return value }
@@ -26,10 +26,10 @@ const setProperty = value => {
26
26
  return f
27
27
  }
28
28
 
29
- /** @type {(_: string) => seq.Sequence<string>} */
29
+ /** @type {(_: string) => seq.List<string>} */
30
30
  const stringSerialize = input => [JSON.stringify(input)]
31
31
 
32
- /** @type {(_: number) => seq.Sequence<string>} */
32
+ /** @type {(_: number) => seq.List<string>} */
33
33
  const numberSerialize = input => [JSON.stringify(input)]
34
34
 
35
35
  const nullSerialize = ['null']
@@ -38,19 +38,19 @@ const trueSerialize = ['true']
38
38
 
39
39
  const falseSerialize = ['false']
40
40
 
41
- /** @type {(_: boolean) => seq.Sequence<string>} */
41
+ /** @type {(_: boolean) => seq.List<string>} */
42
42
  const boolSerialize = value => value ? trueSerialize : falseSerialize
43
43
 
44
44
  const colon = [':']
45
45
  const comma = [',']
46
46
 
47
- /** @type {seq.FoldOperator<seq.Sequence<string>>} */
47
+ /** @type {op.Fold<seq.List<string>>} */
48
48
  const joinOp = a => b => seq.flat([a, comma, b])
49
49
 
50
- /** @type {(input: seq.Sequence<seq.Sequence<string>>) => seq.Sequence<string>} */
50
+ /** @type {(input: seq.List<seq.List<string>>) => seq.List<string>} */
51
51
  const join = seq.fold(joinOp)([])
52
52
 
53
- /** @type {(open: string) => (close: string) => (input: seq.Sequence<seq.Sequence<string>>) => seq.Sequence<string>} */
53
+ /** @type {(open: string) => (close: string) => (input: seq.List<seq.List<string>>) => seq.List<string>} */
54
54
  const list = open => close => {
55
55
  const seqOpen = [open]
56
56
  const seqClose = [close]
@@ -63,19 +63,19 @@ const arrayList = list('[')(']')
63
63
 
64
64
  /** @typedef {object.Entry<Unknown>} Entry*/
65
65
 
66
- /** @typedef {(seq.Sequence<Entry>)} Entries */
66
+ /** @typedef {(seq.List<Entry>)} Entries */
67
67
 
68
68
  /** @typedef {(entries: Entries) => Entries} MapEntries */
69
69
 
70
- /** @type {(mapEntries: MapEntries) => (value: Unknown) => seq.Sequence<string>} */
70
+ /** @type {(mapEntries: MapEntries) => (value: Unknown) => seq.List<string>} */
71
71
  const serialize = sort => {
72
- /** @type {(kv: readonly[string, Unknown]) => seq.Sequence<string>} */
72
+ /** @type {(kv: readonly[string, Unknown]) => seq.List<string>} */
73
73
  const propertySerialize = ([k, v]) => seq.flat([
74
74
  stringSerialize(k),
75
75
  colon,
76
76
  f(v)
77
77
  ])
78
- /** @type {(object: Object) => seq.Sequence<string>} */
78
+ /** @type {(object: Object) => seq.List<string>} */
79
79
  const objectSerialize = input => {
80
80
  const entries = Object.entries(input)
81
81
  const sortedEntries = sort(entries)
@@ -83,12 +83,12 @@ const serialize = sort => {
83
83
  const serializedEntries = seq.map(propertySerialize)(sortedEntries)
84
84
  return objectList(serializedEntries)
85
85
  }
86
- /** @type {(input: Array) => seq.Sequence<string>} */
86
+ /** @type {(input: Array) => seq.List<string>} */
87
87
  const arraySerialize = input => {
88
88
  const serializedEntries = seq.map(f)(input)
89
89
  return arrayList(serializedEntries)
90
90
  }
91
- /** @type {(value: Unknown) => seq.Sequence < string >} */
91
+ /** @type {(value: Unknown) => seq.List < string >} */
92
92
  const f = value => {
93
93
  switch (typeof value) {
94
94
  case 'boolean': { return boolSerialize(value) }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "functionalscript",
3
- "version": "0.0.238",
3
+ "version": "0.0.242",
4
4
  "description": "FunctionalScript is a functional subset of JavaScript",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -14,12 +14,19 @@
14
14
  },
15
15
  "author": "Natfoam",
16
16
  "license": "Apache-2.0",
17
+ "keywords": [
18
+ "lambda",
19
+ "functional-programming",
20
+ "closure",
21
+ "pure-functional",
22
+ "typescript"
23
+ ],
17
24
  "bugs": {
18
25
  "url": "https://github.com/functionalscript/functionalscript/issues"
19
26
  },
20
27
  "homepage": "https://github.com/functionalscript/functionalscript#readme",
21
28
  "devDependencies": {
22
- "@types/node": "^16.11.11",
29
+ "@types/node": "^16.11.12",
23
30
  "typescript": "^4.5.2"
24
31
  }
25
32
  }
package/test.js CHANGED
@@ -1,6 +1,6 @@
1
1
  const i = require('./')
2
2
 
3
- require('./types/sequence/test')
3
+ require('./types/list/test')
4
4
  require('./types/btree/test')
5
5
  require('./json/test')
6
6
  require('./types/object/test')
package/tsconfig.json CHANGED
@@ -33,7 +33,7 @@
33
33
  // "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */
34
34
  // "types": [], /* Specify type package names to be included without being referenced in a source file. */
35
35
  // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
36
- // "resolveJsonModule": true, /* Enable importing .json files */
36
+ "resolveJsonModule": true, /* Enable importing .json files */
37
37
  // "noResolve": true, /* Disallow `import`s, `require`s or `<reference>`s from expanding the number of files TypeScript should add to a project. */
38
38
 
39
39
  /* JavaScript Support */
@@ -1,5 +1,5 @@
1
1
  const option = require('../option')
2
- const seq = require('../sequence')
2
+ const seq = require('../list')
3
3
 
4
4
  /**
5
5
  * @template T
@@ -1,6 +1,6 @@
1
1
  const cmp = require('../function/compare')
2
2
  const { index3, index5 } = cmp
3
- const seq = require('../sequence')
3
+ const seq = require('../list')
4
4
 
5
5
  /**
6
6
  * @template T
@@ -129,41 +129,39 @@ const seq = require('../sequence')
129
129
  const split = ([n0, v1, n2, v3, n4, v5, n6]) => [[n0, v1, n2], v3, [n4, v5, n6]]
130
130
 
131
131
  /**
132
- * @type {<T>(overflow: (o: Branch3<T>) => Result<T>) =>
132
+ * @type {<T>(extend: (o: Branch3<T>) => Result<T>) =>
133
133
  * (replace: (r: Node<T>) => Node<T>) =>
134
134
  * (result: Result<T>) =>
135
135
  * Result<T>}
136
136
  */
137
- const merge = overflow => replace => result => {
137
+ const merge = extend => replace => result => {
138
138
  switch (result[0]) {
139
139
  case 'done': { return result }
140
140
  case 'replace': { return ['replace', replace(result[1])] }
141
- default: { return overflow(result[1]) }
141
+ default: { return extend(result[1]) }
142
142
  }
143
143
  }
144
144
 
145
- /**
146
- * @type {<T>(overflow: (o: Branch3<T>) => Branch5<T>) =>
147
- * (replace: (r: Node<T>) => Branch3<T>) =>
148
- * (result: Result<T>) =>
149
- * Result<T>}
150
- */
151
- const merge2 = overflow => merge(o => ['replace', overflow(o)])
152
-
153
- /**
154
- * @type {<T>(overflow: (o: Branch3<T>) => Branch7<T>) =>
155
- * (replace: (r: Node<T>) => Branch5<T>) =>
156
- * (result: Result<T>) =>
157
- * Result<T>}
158
- */
159
- const merge3 = overflow => merge(o => ['overflow', split(overflow(o))])
160
-
161
145
  /** @type {(visitor: Visitor) => <T>(cmp: Cmp<T>) => (init: Lazy<T>) => (node: Node<T>) => Result<T>} */
162
146
  const visit = ({ found, notFound }) => cmp => {
163
147
  const i3 = index3(cmp)
164
148
  const i5 = index5(cmp)
149
+ /** @typedef {typeof cmp extends Cmp<infer T> ? T : never} T */
150
+ /**
151
+ * @type {(extend: (o: Branch3<T>) => Branch5<T>) =>
152
+ * (replace: (r: Node<T>) => Branch3<T>) =>
153
+ * (result: Result<T>) =>
154
+ * Result<T>}
155
+ */
156
+ const merge2 = extend => merge(o => ['replace', extend(o)])
157
+ /**
158
+ * @type {(extend: (o: Branch3<T>) => Branch7<T>) =>
159
+ * (replace: (r: Node<T>) => Branch5<T>) =>
160
+ * (result: Result<T>) =>
161
+ * Result<T>}
162
+ */
163
+ const merge3 = extend => merge(o => ['overflow', split(extend(o))])
165
164
  return init => {
166
- /** @typedef {typeof cmp extends Cmp<infer T> ? T : never} T*/
167
165
  /** @type {(node: Node<T>) => Result<T>} */
168
166
  const f = node => {
169
167
  switch (node.length) {
@@ -188,14 +186,14 @@ const visit = ({ found, notFound }) => cmp => {
188
186
  switch (i3(v1)) {
189
187
  case 0: {
190
188
  return merge2
191
- (o => [...o, v1, n2])
189
+ (e => [...e, v1, n2])
192
190
  (r => [r, v1, n2])
193
191
  (f(n0))
194
192
  }
195
193
  case 1: { return found.branch3(init)(node) }
196
194
  default: {
197
195
  return merge2
198
- (o => [n0, v1, ...o])
196
+ (e => [n0, v1, ...e])
199
197
  (r => [n0, v1, r])
200
198
  (f(n2))
201
199
  }
@@ -305,7 +303,7 @@ const replaceVisitor = {
305
303
  notFound: notFoundGet,
306
304
  }
307
305
 
308
- /** @type {<T>(node: Node<T>) => seq.Sequence<T>} */
306
+ /** @type {<T>(node: Node<T>) => seq.List<T>} */
309
307
  const values = node => () => {
310
308
  const f = () => {
311
309
  switch (node.length) {
@@ -339,7 +337,7 @@ module.exports = {
339
337
  * @type { <T>(cmp: Cmp<T>) => (node: Node<T>) => T|undefined }
340
338
  */
341
339
  getVisitor: cmp => node => {
342
- const result = visit(getVisitor)(cmp)(() => { throw '' })(node)
340
+ const result = visit(getVisitor)(cmp)(() => { throw 'getVisitor' })(node)
343
341
  if (result[0] === 'done') { return result[1] }
344
342
  return undefined
345
343
  },
@@ -1,7 +1,7 @@
1
1
  const btree = require('.')
2
2
  const { setVisitor, values } = btree
3
3
  const { cmp } = require('../function/compare')
4
- const list = require('../sequence')
4
+ const list = require('../list')
5
5
 
6
6
  /** @type {(node: btree.Node<string>) => (value: string) => btree.Node<string>} */
7
7
  const set = node => value => {
@@ -22,7 +22,7 @@ const test = () => {
22
22
  _map = set(_map)('f')
23
23
  //
24
24
  {
25
- /** @type {import('../sequence').Result<string>} */
25
+ /** @type {list.Result<string>} */
26
26
  let _item = list.next(values(_map))
27
27
  while (_item !== undefined) {
28
28
  _item = list.next(_item.tail)
@@ -2,44 +2,76 @@
2
2
  * @template A
3
3
  * @template B
4
4
  * @template R
5
- * @typedef {(a: A) => (b: B) => R} BinaryOperator
5
+ * @typedef {(a: A) => (b: B) => R} Binary
6
6
  */
7
7
 
8
8
  /**
9
- * @template R
10
- * @template T
11
- * @typedef {BinaryOperator<R, T, R>} ReduceOperator
9
+ * @template I,O
10
+ * @typedef {Binary<O, I, O>} Reduce
12
11
  */
13
12
 
14
- /** @type {(separator: string) => ReduceOperator<string, string>} */
13
+ /** @type {(separator: string) => Fold<string>} */
15
14
  const join = separator => prior => value => `${prior}${separator}${value}`
16
15
 
17
- /** @type {(sum: number) => (value: number) => number} */
16
+ /** @type {Fold<number>} */
18
17
  const addition = a => b => a + b
19
18
 
20
19
  /**
21
20
  * @template T
22
21
  * @template R
23
- * @typedef {(value: T) => R} UnaryOperator
22
+ * @typedef {(value: T) => R} Unary
24
23
  */
25
24
 
26
- /** @type {(value: boolean) => boolean} */
25
+ /** @type {Unary<boolean, boolean>} */
27
26
  const logicalNot = v => !v
28
27
 
29
28
  /**
30
29
  * @template T
31
- * @typedef {(a: T) => (b: T) => boolean} EqualOperator
30
+ * @typedef {Binary<T, T, boolean>} Equal
32
31
  */
33
32
 
34
33
  /** @type {<T>(a: T) => (b: T) => boolean} */
35
34
  const strictEqual = a => b => a === b
36
35
 
37
- /** @type {ReduceOperator<number, number>} */
36
+ /** @type {Fold<number>} */
38
37
  const min = a => b => a < b ? a : b
39
38
 
40
- /** @type {ReduceOperator<number, number>} */
39
+ /** @type {Fold<number>} */
41
40
  const max = a => b => a > b ? a : b
42
41
 
42
+ /**
43
+ * @template I,O
44
+ * @typedef {(input: I) => readonly[O, Scan<I,O>]} Scan
45
+ */
46
+
47
+ /**
48
+ * @template I,S,O
49
+ * @typedef {(prior: S) => (input: I) => readonly[O, S]} StateScan
50
+ */
51
+
52
+ /** @type {<I, S, O>(op: StateScan<I, S, O>) => (prior: S) => Scan<I, O>} */
53
+ const stateScanToScan = op => prior => i => {
54
+ const [o, s] = op(prior)(i)
55
+ return [o, stateScanToScan(op)(s)]
56
+ }
57
+
58
+ /** @type {<I, O>(reduce: Reduce<I, O>) => (prior: O) => Scan<I, O>} */
59
+ const reduceToScan = reduce => prior => i => {
60
+ const result = reduce(prior)(i)
61
+ return [result, reduceToScan(reduce)(result)]
62
+ }
63
+
64
+ /**
65
+ * @template T
66
+ * @typedef {Reduce<T, T>} Fold
67
+ */
68
+
69
+ /** @type {<T>(fold: Fold<T>) => Scan<T, T>} */
70
+ const foldToScan = op => init => [init, reduceToScan(op)(init)]
71
+
72
+ /** @type {(a: number) => () => number} */
73
+ const counter = a => () => a + 1
74
+
43
75
  module.exports = {
44
76
  /** @readonly */
45
77
  join,
@@ -53,4 +85,12 @@ module.exports = {
53
85
  min,
54
86
  /** @readonly */
55
87
  max,
88
+ /** @readonly */
89
+ stateScanToScan,
90
+ /** @readonly */
91
+ reduceToScan,
92
+ /** @readonly */
93
+ foldToScan,
94
+ /** @readonly */
95
+ counter,
56
96
  }