functionalscript 0.0.303 → 0.0.307
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/commonjs/path/index.js +5 -5
- package/package.json +1 -1
- package/sha2/index.js +49 -34
- package/sha2/test.js +11 -4
- package/types/array/index.js +2 -0
- package/types/function/operator/index.js +7 -2
- package/types/list/index.js +42 -28
- package/types/list/test.js +6 -0
package/commonjs/path/index.js
CHANGED
|
@@ -21,18 +21,18 @@ const split = path => path.split('/')
|
|
|
21
21
|
/** @typedef {readonly[list.List<string>] | undefined} OptionList */
|
|
22
22
|
|
|
23
23
|
/** @type {(s: OptionList) => (items: string) => OptionList} */
|
|
24
|
-
const normItemsOp = prior =>
|
|
24
|
+
const normItemsOp = prior => first => {
|
|
25
25
|
if (prior === undefined) { return undefined }
|
|
26
|
-
const
|
|
27
|
-
switch (
|
|
26
|
+
const tail = prior[0]
|
|
27
|
+
switch (first) {
|
|
28
28
|
case '': case '.': { return prior }
|
|
29
29
|
case '..': {
|
|
30
|
-
const result = list.next(
|
|
30
|
+
const result = list.next(tail)
|
|
31
31
|
if (result === undefined) { return undefined }
|
|
32
32
|
return [result.tail]
|
|
33
33
|
}
|
|
34
34
|
default: {
|
|
35
|
-
return [
|
|
35
|
+
return [{ first, tail }]
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
}
|
package/package.json
CHANGED
package/sha2/index.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
const array = require('../types/array')
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* @typedef {{
|
|
3
5
|
* readonly f: (i: number) => number
|
|
@@ -5,12 +7,12 @@
|
|
|
5
7
|
* }} HashInput
|
|
6
8
|
*/
|
|
7
9
|
|
|
8
|
-
/** @typedef {
|
|
10
|
+
/** @typedef {array.Array8<number>} Hash8 */
|
|
9
11
|
|
|
10
|
-
/** @typedef {
|
|
12
|
+
/** @typedef {array.Array16<number>} Array16 */
|
|
11
13
|
|
|
12
14
|
/** @type {(input: number) => (pos: number) => number} */
|
|
13
|
-
const
|
|
15
|
+
const appendOneWithZeros = input => pos => (input >> pos << pos) | (1 << pos)
|
|
14
16
|
|
|
15
17
|
/** @type {(input: number) => (pos: number) => number} */
|
|
16
18
|
const mod = a => b => (a % b + b) % b
|
|
@@ -24,7 +26,7 @@ const padding = input => bitsCount => {
|
|
|
24
26
|
i < appendBlockIndex ?
|
|
25
27
|
input[i] :
|
|
26
28
|
i === appendBlockIndex ?
|
|
27
|
-
(appendBlockIndex >= input.length ? 0x8000_0000 :
|
|
29
|
+
(appendBlockIndex >= input.length ? 0x8000_0000 : appendOneWithZeros(input[appendBlockIndex])(31 - bitsCount % 32)) :
|
|
28
30
|
i === length - 2 ?
|
|
29
31
|
(bitsCount / 0x1_0000_0000) | 0 :
|
|
30
32
|
i === length - 1 ?
|
|
@@ -72,46 +74,59 @@ const smallSigma0 = smallSigma(7)(18)(3)
|
|
|
72
74
|
const smallSigma1 = smallSigma(17)(19)(10)
|
|
73
75
|
|
|
74
76
|
/** @type {Hash8} */
|
|
75
|
-
const init256 =
|
|
77
|
+
const init256 = [0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19]
|
|
76
78
|
|
|
77
79
|
/** @type {(input: readonly number[]) => (bitsCount: number) => Hash8} */
|
|
78
80
|
const computeSha256 = input => bitsCount => compute(input)(bitsCount)(init256)
|
|
79
81
|
|
|
80
82
|
/** @type {Hash8} */
|
|
81
|
-
const init224 =
|
|
83
|
+
const init224 = [0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4]
|
|
82
84
|
|
|
83
85
|
const k = [
|
|
84
|
-
|
|
86
|
+
[
|
|
85
87
|
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
|
86
|
-
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174]
|
|
87
|
-
|
|
88
|
+
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174],
|
|
89
|
+
[
|
|
88
90
|
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
|
89
|
-
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967]
|
|
90
|
-
|
|
91
|
+
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967],
|
|
92
|
+
[
|
|
91
93
|
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
|
92
|
-
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070]
|
|
93
|
-
|
|
94
|
+
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070],
|
|
95
|
+
[
|
|
94
96
|
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
|
95
|
-
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2]
|
|
97
|
+
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2],
|
|
96
98
|
];
|
|
97
99
|
|
|
98
100
|
/** @type {(input: readonly number[]) => (bitsCount: number) => Hash8} */
|
|
99
101
|
const computeSha224 = input => bitsCount => compute(input)(bitsCount)(init224)
|
|
100
102
|
|
|
103
|
+
/** @type {(a: array.Array4<number>) => number} */
|
|
104
|
+
const wi = a => (smallSigma1(a[0]) + a[1] + smallSigma0(a[2]) + a[3]) | 0
|
|
105
|
+
|
|
101
106
|
/** @type {(input: Array16) => Array16} */
|
|
102
107
|
const nextW = w => {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
108
|
+
const _0 = wi([w[14], w[ 9], w[ 1], w[ 0]])
|
|
109
|
+
const _1 = wi([w[15], w[10], w[ 2], w[ 1]])
|
|
110
|
+
const _2 = wi([ _0, w[11], w[ 3], w[ 2]])
|
|
111
|
+
const _3 = wi([ _1, w[12], w[ 4], w[ 3]])
|
|
112
|
+
const _4 = wi([ _2, w[13], w[ 5], w[ 4]])
|
|
113
|
+
const _5 = wi([ _3, w[14], w[ 6], w[ 5]])
|
|
114
|
+
const _6 = wi([ _4, w[15], w[ 7], w[ 6]])
|
|
115
|
+
const _7 = wi([ _5, _0, w[ 8], w[ 7]])
|
|
116
|
+
const _8 = wi([ _6, _1, w[ 9], w[ 8]])
|
|
117
|
+
const _9 = wi([ _7, _2, w[10], w[ 9]])
|
|
118
|
+
const _A = wi([ _8, _3, w[11], w[10]])
|
|
119
|
+
const _B = wi([ _9, _4, w[12], w[11]])
|
|
120
|
+
const _C = wi([ _A, _5, w[13], w[12]])
|
|
121
|
+
const _D = wi([ _B, _6, w[14], w[13]])
|
|
122
|
+
const _E = wi([ _C, _7, w[15], w[14]])
|
|
123
|
+
const _F = wi([ _D, _8, _0, w[15]])
|
|
124
|
+
return [_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _A, _B, _C, _D, _E, _F]
|
|
107
125
|
}
|
|
108
126
|
|
|
109
127
|
/** @type {(init: Hash8) => (data: Array16) => Hash8} */
|
|
110
128
|
const compress = init => data => {
|
|
111
|
-
let w =
|
|
112
|
-
for (let t = 0; t < 16; t++) {
|
|
113
|
-
w[t] = data[t]
|
|
114
|
-
}
|
|
129
|
+
let w = data
|
|
115
130
|
|
|
116
131
|
let a = init[0]
|
|
117
132
|
let b = init[1]
|
|
@@ -139,16 +154,16 @@ const compress = init => data => {
|
|
|
139
154
|
w = nextW(w)
|
|
140
155
|
}
|
|
141
156
|
|
|
142
|
-
return
|
|
143
|
-
init[0] + a,
|
|
144
|
-
init[1] + b,
|
|
145
|
-
init[2] + c,
|
|
146
|
-
init[3] + d,
|
|
147
|
-
init[4] + e,
|
|
148
|
-
init[5] + f,
|
|
149
|
-
init[6] + g,
|
|
150
|
-
init[7] + h,
|
|
151
|
-
]
|
|
157
|
+
return [
|
|
158
|
+
(init[0] + a) | 0,
|
|
159
|
+
(init[1] + b) | 0,
|
|
160
|
+
(init[2] + c) | 0,
|
|
161
|
+
(init[3] + d) | 0,
|
|
162
|
+
(init[4] + e) | 0,
|
|
163
|
+
(init[5] + f) | 0,
|
|
164
|
+
(init[6] + g) | 0,
|
|
165
|
+
(init[7] + h) | 0,
|
|
166
|
+
]
|
|
152
167
|
}
|
|
153
168
|
|
|
154
169
|
/** @type {(input: readonly number[]) => (bitsCount: number) => (init: Hash8) => Hash8} */
|
|
@@ -160,9 +175,9 @@ const compute = input => bitsCount => init => {
|
|
|
160
175
|
const chunkCount = length / 16
|
|
161
176
|
for (let i = 0; i < chunkCount; i++) {
|
|
162
177
|
const s = i * 16
|
|
163
|
-
result = compress(result)(
|
|
178
|
+
result = compress(result)([
|
|
164
179
|
f(s + 0), f(s + 1), f(s + 2), f(s + 3), f(s + 4), f(s + 5), f(s + 6), f(s + 7),
|
|
165
|
-
f(s + 8), f(s + 9), f(s + 10), f(s + 11), f(s + 12), f(s + 13), f(s + 14), f(s + 15)])
|
|
180
|
+
f(s + 8), f(s + 9), f(s + 10), f(s + 11), f(s + 12), f(s + 13), f(s + 14), f(s + 15)])
|
|
166
181
|
}
|
|
167
182
|
|
|
168
183
|
return result
|
package/sha2/test.js
CHANGED
|
@@ -34,20 +34,27 @@ const stringify = a => json.stringify(sort)(a)
|
|
|
34
34
|
|
|
35
35
|
{
|
|
36
36
|
const hash = _.computeSha256([])(0)
|
|
37
|
-
const result = stringify(
|
|
37
|
+
const result = stringify(hash.map(toHexString))
|
|
38
38
|
if (result !== '["e3b0c442","98fc1c14","9afbf4c8","996fb924","27ae41e4","649b934c","a495991b","7852b855"]') { throw result }
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
{
|
|
42
42
|
const hash = _.computeSha224([])(0)
|
|
43
|
-
const result = stringify(
|
|
43
|
+
const result = stringify(hash.map(toHexString))
|
|
44
44
|
if (result !== '["d14a028c","2a3a2bc9","476102bb","288234c4","15a2b01f","828ea62a","c5b3e42f","bdd387cb"]') { throw result }
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
{
|
|
48
48
|
//[0x68656C6C, 0x6F20776F, 0x726C6400] represents phrase 'hello world'
|
|
49
49
|
const hash = _.computeSha256([0x68656C6C, 0x6F20776F, 0x726C6400])(88)
|
|
50
|
-
const result = stringify(
|
|
50
|
+
const result = stringify(hash.map(toHexString))
|
|
51
|
+
if (result !== '["b94d27b9","934d3e08","a52e52d7","da7dabfa","c484efe3","7a5380ee","9088f7ac","e2efcde9"]') { throw result }
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
{
|
|
55
|
+
//[0x68656C6C, 0x6F20776F, 0x726C6488] represents phrase 'hello world' with 1's at the end
|
|
56
|
+
const hash = _.computeSha256([0x68656C6C, 0x6F20776F, 0x726C64FF])(88)
|
|
57
|
+
const result = stringify(hash.map(toHexString))
|
|
51
58
|
if (result !== '["b94d27b9","934d3e08","a52e52d7","da7dabfa","c484efe3","7a5380ee","9088f7ac","e2efcde9"]') { throw result }
|
|
52
59
|
}
|
|
53
60
|
|
|
@@ -60,7 +67,7 @@ const stringify = a => json.stringify(sort)(a)
|
|
|
60
67
|
{
|
|
61
68
|
const input = Array(16).fill(0x31313131)
|
|
62
69
|
const hash = _.computeSha256(input)(512)
|
|
63
|
-
const result = stringify(
|
|
70
|
+
const result = stringify(hash.map(toHexString))
|
|
64
71
|
if (result !== '["3138bb9b","c78df27c","473ecfd1","410f7bd4","5ebac1f5","9cf3ff9c","fe4db77a","ab7aedd3"]') { throw result }
|
|
65
72
|
}
|
|
66
73
|
|
package/types/array/index.js
CHANGED
|
@@ -57,6 +57,8 @@ const seq = require('../list')
|
|
|
57
57
|
* @typedef {readonly[T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T]} Array16
|
|
58
58
|
*/
|
|
59
59
|
|
|
60
|
+
/** @typedef {0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15} Index16 */
|
|
61
|
+
|
|
60
62
|
/**
|
|
61
63
|
* @template T
|
|
62
64
|
* @typedef {Array1<T>| Array2<T> | Array3<T> | Array4<T> | Array5<T>} Array1_5
|
|
@@ -13,6 +13,9 @@
|
|
|
13
13
|
/** @type {(separator: string) => Fold<string>} */
|
|
14
14
|
const join = separator => prior => value => `${prior}${separator}${value}`
|
|
15
15
|
|
|
16
|
+
/** @type {Fold<string>} */
|
|
17
|
+
const concat = a => b => `${a}${b}`
|
|
18
|
+
|
|
16
19
|
/** @type {Fold<number>} */
|
|
17
20
|
const addition = a => b => a + b
|
|
18
21
|
|
|
@@ -26,8 +29,8 @@ const addition = a => b => a + b
|
|
|
26
29
|
const logicalNot = v => !v
|
|
27
30
|
|
|
28
31
|
/**
|
|
29
|
-
* @template T
|
|
30
|
-
* @typedef {Binary<T, T, boolean>} Equal
|
|
32
|
+
* @template T
|
|
33
|
+
* @typedef {Binary<T, T, boolean>} Equal
|
|
31
34
|
*/
|
|
32
35
|
|
|
33
36
|
/** @type {<T>(a: T) => (b: T) => boolean} */
|
|
@@ -93,4 +96,6 @@ module.exports = {
|
|
|
93
96
|
foldToScan,
|
|
94
97
|
/** @readonly */
|
|
95
98
|
counter,
|
|
99
|
+
/** @readonly */
|
|
100
|
+
concat,
|
|
96
101
|
}
|
package/types/list/index.js
CHANGED
|
@@ -44,14 +44,13 @@ const { logicalNot, strictEqual, stateScanToScan, reduceToScan, foldToScan } = r
|
|
|
44
44
|
* }} Concat
|
|
45
45
|
*/
|
|
46
46
|
|
|
47
|
-
/** @type {<T>(first: T) => (tail: List<T>) => NonEmpty<T>} */
|
|
48
|
-
const nonEmpty = first => tail => ({ first, tail })
|
|
49
|
-
|
|
50
|
-
/** @type {(i: number) => <T>(array: readonly T[]) => Result<T>} */
|
|
51
|
-
const fromArrayAt = i => array => i < array.length ? nonEmpty(array[i])(() => fromArrayAt(i + 1)(array)) : undefined
|
|
52
|
-
|
|
53
47
|
/** @type {<T>(array: readonly T[]) => Result<T>} */
|
|
54
|
-
const fromArray =
|
|
48
|
+
const fromArray = array => {
|
|
49
|
+
/** @typedef {typeof array extends readonly (infer T)[] ? T : never} T */
|
|
50
|
+
/** @type {(i: number) => Result<T>} */
|
|
51
|
+
const at = i => i < array.length ? { first: array[i], tail: () => at(i + 1) } : undefined
|
|
52
|
+
return at(0)
|
|
53
|
+
}
|
|
55
54
|
|
|
56
55
|
/** @type {<T>(a: List<T>) => (b: List<T>) => List<T>} */
|
|
57
56
|
const concat = a => b => b === undefined ? a : ({ isConcat: true, a, b })
|
|
@@ -78,7 +77,7 @@ const next = list => {
|
|
|
78
77
|
}
|
|
79
78
|
|
|
80
79
|
if (a !== undefined) {
|
|
81
|
-
return
|
|
80
|
+
return { first: a.first, tail: concat(a.tail)(b) }
|
|
82
81
|
}
|
|
83
82
|
|
|
84
83
|
if (b === undefined) { return undefined }
|
|
@@ -120,7 +119,7 @@ const flatStep = n => concat(n.first)(flat(n.tail))
|
|
|
120
119
|
const flat = apply(flatStep)
|
|
121
120
|
|
|
122
121
|
/** @type {<I, O>(f: (value: I) => O) => (n: NonEmpty<I>) => List<O>} */
|
|
123
|
-
const mapStep = f => n =>
|
|
122
|
+
const mapStep = f => n => ({ first: f(n.first), tail: map(f)(n.tail) })
|
|
124
123
|
|
|
125
124
|
/** @type {<I, O>(f: (value: I) => O) => (input: List<I>) => List<O>} */
|
|
126
125
|
const map = f => apply(mapStep(f))
|
|
@@ -131,7 +130,7 @@ const flatMap = f => compose(map(f))(flat)
|
|
|
131
130
|
/** @type {<T>(f: (value: T) => boolean) => (n: NonEmpty<T>) => List<T>} */
|
|
132
131
|
const filterStep = f => n => {
|
|
133
132
|
const tail = filter(f)(n.tail)
|
|
134
|
-
return f(n.first) ?
|
|
133
|
+
return f(n.first) ? { first: n.first, tail } : tail
|
|
135
134
|
}
|
|
136
135
|
|
|
137
136
|
/** @type {<T>(f: (value: T) => boolean) => (input: List<T>) => List<T>} */
|
|
@@ -140,20 +139,20 @@ const filter = f => apply(filterStep(f))
|
|
|
140
139
|
/** @type {<I, O>(f: (value: I) => O|undefined) => (n: NonEmpty<I>) => List<O>} */
|
|
141
140
|
const filterMapStep = f => n => {
|
|
142
141
|
const [first, tail] = [f(n.first), filterMap(f)(n.tail)]
|
|
143
|
-
return first === undefined ? tail :
|
|
142
|
+
return first === undefined ? tail : { first, tail }
|
|
144
143
|
}
|
|
145
144
|
|
|
146
145
|
/** @type {<I, O>(f: (value: I) => O|undefined) => (input: List<I>) => List<O>} */
|
|
147
146
|
const filterMap = f => apply(filterMapStep(f))
|
|
148
147
|
|
|
149
148
|
/** @type {<T>(f: (value: T) => boolean) => (n: NonEmpty<T>) => List<T>} */
|
|
150
|
-
const takeWhileStep = f => n => f(n.first) ?
|
|
149
|
+
const takeWhileStep = f => n => f(n.first) ? { first: n.first, tail: takeWhile(f)(n.tail) } : undefined
|
|
151
150
|
|
|
152
151
|
/** @type {<T>(f: (value: T) => boolean) => (input: List<T>) => List<T>} */
|
|
153
152
|
const takeWhile = f => apply(takeWhileStep(f))
|
|
154
153
|
|
|
155
154
|
/** @type {(n: number) => <T>(result: NonEmpty<T>) => List<T>} */
|
|
156
|
-
const takeStep = n => ne => 0 < n ?
|
|
155
|
+
const takeStep = n => ne => 0 < n ? { first: ne.first, tail: take(n - 1)(ne.tail) } : undefined
|
|
157
156
|
|
|
158
157
|
/** @type {(n: number) => <T>(input: List<T>) => List<T>} */
|
|
159
158
|
const take = n => apply(takeStep(n))
|
|
@@ -177,10 +176,11 @@ const first = def => input => {
|
|
|
177
176
|
return result.first
|
|
178
177
|
}
|
|
179
178
|
|
|
180
|
-
/** @type {<D>(
|
|
181
|
-
const last =
|
|
182
|
-
/** @typedef {typeof
|
|
183
|
-
|
|
179
|
+
/** @type {<D>(first: D) => <T>(tail: List<T>) => D|T} */
|
|
180
|
+
const last = first => tail => {
|
|
181
|
+
/** @typedef {typeof tail extends List<infer T> ? T : never} T */
|
|
182
|
+
/** @type {NonEmpty<typeof first|T>} */
|
|
183
|
+
let i = { first, tail }
|
|
184
184
|
while (true) {
|
|
185
185
|
const result = next(i.tail)
|
|
186
186
|
if (result === undefined) {
|
|
@@ -212,19 +212,19 @@ const includes = value => input => some(map(strictEqual(value))(input))
|
|
|
212
212
|
const countdown = count => () => {
|
|
213
213
|
if (count <= 0) { return undefined }
|
|
214
214
|
const first = count - 1
|
|
215
|
-
return
|
|
215
|
+
return { first, tail: countdown(first) }
|
|
216
216
|
}
|
|
217
217
|
|
|
218
218
|
/** @type {<T>(list: List<T>) => List<T>} */
|
|
219
219
|
const cycle = list => () => {
|
|
220
220
|
const i = next(list)
|
|
221
|
-
return i === undefined ? undefined :
|
|
221
|
+
return i === undefined ? undefined : { first: i.first, tail: concat(i.tail)(cycle(list)) }
|
|
222
222
|
}
|
|
223
223
|
|
|
224
224
|
/** @type {<I, O>(op: operator.Scan<I, O>) => (ne: NonEmpty<I>) => List<O>} */
|
|
225
225
|
const scanStep = op => ne => {
|
|
226
|
-
const [
|
|
227
|
-
return
|
|
226
|
+
const [first, newOp] = op(ne.first)
|
|
227
|
+
return { first, tail: scan(newOp)(ne.tail) }
|
|
228
228
|
}
|
|
229
229
|
|
|
230
230
|
/** @type {<I, O>(op: operator.Scan<I, O>) => (input: List<I>) => List<O>} */
|
|
@@ -263,13 +263,13 @@ const length = reduce(operator.counter)(0)
|
|
|
263
263
|
const entryOperator = index => value => [[index, value], index + 1]
|
|
264
264
|
|
|
265
265
|
/** @type {<T>(input: List<T>) => List<Entry<T>>} */
|
|
266
|
-
const entries =
|
|
266
|
+
const entries = input => {
|
|
267
267
|
/** @typedef {typeof input extends List<infer T> ? T : never} T */
|
|
268
268
|
return stateScan(/** @type {operator.StateScan<T, Number, Entry<T>>} */(entryOperator))(0)(input)
|
|
269
269
|
}
|
|
270
270
|
|
|
271
271
|
/** @type {<T>(prior: List<T>) => (value: T) => List<T>} */
|
|
272
|
-
const reverseOperator =
|
|
272
|
+
const reverseOperator = tail => first => ({ first, tail })
|
|
273
273
|
|
|
274
274
|
/** @type {<T>(input: List<T>) => List<T>} */
|
|
275
275
|
const reverse = reduce(reverseOperator)(undefined)
|
|
@@ -283,26 +283,36 @@ const zip = a => b => () => {
|
|
|
283
283
|
if (aResult === undefined) { return undefined }
|
|
284
284
|
const bResult = next(b)
|
|
285
285
|
if (bResult === undefined) { return undefined }
|
|
286
|
-
return
|
|
286
|
+
return { first: tuple2(aResult.first)(bResult.first), tail: zip(aResult.tail)(bResult.tail) }
|
|
287
287
|
}
|
|
288
288
|
|
|
289
289
|
/** @type {<T>(e: operator.Equal<T>) => (a: List<T>) => (b: List<T>) => List<boolean>} */
|
|
290
290
|
const equalZip = e => a => b => () => {
|
|
291
291
|
const [aResult, bResult] = [next(a), next(b)]
|
|
292
292
|
return aResult === undefined || bResult === undefined
|
|
293
|
-
?
|
|
294
|
-
:
|
|
293
|
+
? { first: aResult === bResult, tail: undefined }
|
|
294
|
+
: { first: e(aResult.first)(bResult.first), tail: equalZip(e)(aResult.tail)(bResult.tail) }
|
|
295
295
|
}
|
|
296
296
|
|
|
297
297
|
/** @type {<T>(e: operator.Equal<T>) => (a: List<T>) => (b: List<T>) => boolean} */
|
|
298
298
|
const equal = e => a => b => every(equalZip(e)(a)(b))
|
|
299
299
|
|
|
300
|
+
/** @type {(s: string) => List<number>} */
|
|
301
|
+
const toCharCodes = s => {
|
|
302
|
+
/** @type {(i: number) => Result<number>} */
|
|
303
|
+
const at = i => {
|
|
304
|
+
const first = s.charCodeAt(i)
|
|
305
|
+
return isNaN(first) ? undefined : { first, tail: () => at(i + 1) }
|
|
306
|
+
}
|
|
307
|
+
return at(0)
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
const fromCharCodes = compose(map(String.fromCharCode))(fold(operator.concat)(''))
|
|
311
|
+
|
|
300
312
|
module.exports = {
|
|
301
313
|
/** @readonly */
|
|
302
314
|
empty: undefined,
|
|
303
315
|
/** @readonly */
|
|
304
|
-
nonEmpty,
|
|
305
|
-
/** @readonly */
|
|
306
316
|
concat,
|
|
307
317
|
/** @readonly */
|
|
308
318
|
next,
|
|
@@ -374,4 +384,8 @@ module.exports = {
|
|
|
374
384
|
zip,
|
|
375
385
|
/** @readonly */
|
|
376
386
|
equal,
|
|
387
|
+
/** @readonly */
|
|
388
|
+
toCharCodes,
|
|
389
|
+
/** @readonly */
|
|
390
|
+
fromCharCodes,
|
|
377
391
|
}
|
package/types/list/test.js
CHANGED
|
@@ -234,6 +234,12 @@ const stringify = sequence => json.stringify(sort)(_.toArray(sequence))
|
|
|
234
234
|
if (result !== false) { throw result }
|
|
235
235
|
}
|
|
236
236
|
|
|
237
|
+
{
|
|
238
|
+
const r = _.toCharCodes("Hello world!")
|
|
239
|
+
const x = _.fromCharCodes(r)
|
|
240
|
+
if (x !== "Hello world!") { throw x }
|
|
241
|
+
}
|
|
242
|
+
|
|
237
243
|
// stress tests
|
|
238
244
|
|
|
239
245
|
const stress = () => {
|