@satoshibits/functional 1.1.0 → 1.1.2
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/README.md +28 -145
- package/dist/array-utils.d.mts +13 -0
- package/dist/array-utils.d.mts.map +1 -1
- package/dist/array-utils.mjs +13 -0
- package/dist/array-utils.mjs.map +1 -1
- package/dist/array-utils.test.d.ts +2 -0
- package/dist/array-utils.test.d.ts.map +1 -0
- package/dist/array-utils.test.js +256 -0
- package/dist/array-utils.test.js.map +1 -0
- package/dist/composition.d.mts +13 -0
- package/dist/composition.d.mts.map +1 -1
- package/dist/composition.mjs +13 -0
- package/dist/composition.mjs.map +1 -1
- package/dist/composition.test.d.ts +2 -0
- package/dist/composition.test.d.ts.map +1 -0
- package/dist/composition.test.js +409 -0
- package/dist/composition.test.js.map +1 -0
- package/dist/integration.test.d.mts +2 -0
- package/dist/integration.test.d.mts.map +1 -0
- package/dist/integration.test.mjs +486 -0
- package/dist/integration.test.mjs.map +1 -0
- package/dist/io.d.mts +12 -0
- package/dist/io.d.mts.map +1 -1
- package/dist/io.mjs +12 -0
- package/dist/io.mjs.map +1 -1
- package/dist/io.test.d.mts +2 -0
- package/dist/io.test.d.mts.map +1 -0
- package/dist/io.test.mjs +373 -0
- package/dist/io.test.mjs.map +1 -0
- package/dist/laws.test.d.mts +2 -0
- package/dist/laws.test.d.mts.map +1 -0
- package/dist/laws.test.mjs +614 -0
- package/dist/laws.test.mjs.map +1 -0
- package/dist/object-utils.d.mts +11 -0
- package/dist/object-utils.d.mts.map +1 -1
- package/dist/object-utils.mjs +11 -0
- package/dist/object-utils.mjs.map +1 -1
- package/dist/object-utils.test.d.ts +2 -0
- package/dist/object-utils.test.d.ts.map +1 -0
- package/dist/object-utils.test.js +286 -0
- package/dist/object-utils.test.js.map +1 -0
- package/dist/option-additions.test.d.mts +2 -0
- package/dist/option-additions.test.d.mts.map +1 -0
- package/dist/option-additions.test.mjs +325 -0
- package/dist/option-additions.test.mjs.map +1 -0
- package/dist/option.d.mts +20 -3
- package/dist/option.d.mts.map +1 -1
- package/dist/option.mjs +20 -3
- package/dist/option.mjs.map +1 -1
- package/dist/option.test.d.ts +6 -0
- package/dist/option.test.d.ts.map +1 -0
- package/dist/option.test.js +606 -0
- package/dist/option.test.js.map +1 -0
- package/dist/performance.d.mts +26 -9
- package/dist/performance.d.mts.map +1 -1
- package/dist/performance.mjs +26 -9
- package/dist/performance.mjs.map +1 -1
- package/dist/performance.test.d.ts +2 -0
- package/dist/performance.test.d.ts.map +1 -0
- package/dist/performance.test.js +424 -0
- package/dist/performance.test.js.map +1 -0
- package/dist/pipeline.d.mts +12 -0
- package/dist/pipeline.d.mts.map +1 -1
- package/dist/pipeline.mjs +12 -0
- package/dist/pipeline.mjs.map +1 -1
- package/dist/pipeline.test.d.ts +2 -0
- package/dist/pipeline.test.d.ts.map +1 -0
- package/dist/pipeline.test.js +445 -0
- package/dist/pipeline.test.js.map +1 -0
- package/dist/predicates.d.mts +12 -0
- package/dist/predicates.d.mts.map +1 -1
- package/dist/predicates.mjs +12 -0
- package/dist/predicates.mjs.map +1 -1
- package/dist/predicates.test.d.ts +2 -0
- package/dist/predicates.test.d.ts.map +1 -0
- package/dist/predicates.test.js +375 -0
- package/dist/predicates.test.js.map +1 -0
- package/dist/reader-result.d.mts +37 -16
- package/dist/reader-result.d.mts.map +1 -1
- package/dist/reader-result.mjs +37 -16
- package/dist/reader-result.mjs.map +1 -1
- package/dist/reader-result.test.d.ts +2 -0
- package/dist/reader-result.test.d.ts.map +1 -0
- package/dist/reader-result.test.js +1259 -0
- package/dist/reader-result.test.js.map +1 -0
- package/dist/reader.d.mts +12 -0
- package/dist/reader.d.mts.map +1 -1
- package/dist/reader.mjs +12 -0
- package/dist/reader.mjs.map +1 -1
- package/dist/reader.test.d.mts +2 -0
- package/dist/reader.test.d.mts.map +1 -0
- package/dist/reader.test.mjs +288 -0
- package/dist/reader.test.mjs.map +1 -0
- package/dist/result-additions.test.d.mts +2 -0
- package/dist/result-additions.test.d.mts.map +1 -0
- package/dist/result-additions.test.mjs +325 -0
- package/dist/result-additions.test.mjs.map +1 -0
- package/dist/result.d.mts +12 -0
- package/dist/result.d.mts.map +1 -1
- package/dist/result.mjs +12 -0
- package/dist/result.mjs.map +1 -1
- package/dist/result.test.d.ts +2 -0
- package/dist/result.test.d.ts.map +1 -0
- package/dist/result.test.js +453 -0
- package/dist/result.test.js.map +1 -0
- package/dist/task.d.mts +13 -0
- package/dist/task.d.mts.map +1 -1
- package/dist/task.mjs +13 -0
- package/dist/task.mjs.map +1 -1
- package/dist/task.test.d.mts +2 -0
- package/dist/task.test.d.mts.map +1 -0
- package/dist/task.test.mjs +1006 -0
- package/dist/task.test.mjs.map +1 -0
- package/dist/types.d.mts +12 -0
- package/dist/types.d.mts.map +1 -1
- package/dist/types.mjs +12 -0
- package/dist/types.mjs.map +1 -1
- package/dist/types.test.d.ts +6 -0
- package/dist/types.test.d.ts.map +1 -0
- package/dist/types.test.js +447 -0
- package/dist/types.test.js.map +1 -0
- package/dist/validation.d.mts +12 -0
- package/dist/validation.d.mts.map +1 -1
- package/dist/validation.mjs +12 -0
- package/dist/validation.mjs.map +1 -1
- package/dist/validation.test.d.ts +2 -0
- package/dist/validation.test.d.ts.map +1 -0
- package/dist/validation.test.js +518 -0
- package/dist/validation.test.js.map +1 -0
- package/package.json +77 -13
|
@@ -0,0 +1,614 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
13
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
+
function step(op) {
|
|
16
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
18
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
19
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
+
switch (op[0]) {
|
|
21
|
+
case 0: case 1: t = op; break;
|
|
22
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
+
default:
|
|
26
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
+
if (t[2]) _.ops.pop();
|
|
31
|
+
_.trys.pop(); continue;
|
|
32
|
+
}
|
|
33
|
+
op = body.call(thisArg, _);
|
|
34
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
import { describe, expect, it } from "vitest";
|
|
39
|
+
import { IO } from "./io.mjs";
|
|
40
|
+
import { none, Option, some } from "./option.mjs";
|
|
41
|
+
import { Reader } from "./reader.mjs";
|
|
42
|
+
import { Result } from "./result.mjs";
|
|
43
|
+
import { Task } from "./task.mjs";
|
|
44
|
+
/**
|
|
45
|
+
* Algebraic law tests for functional types.
|
|
46
|
+
* These tests verify that our implementations satisfy the mathematical laws
|
|
47
|
+
* required for functors, monads, and applicatives.
|
|
48
|
+
*/
|
|
49
|
+
describe("Algebraic Laws", function () {
|
|
50
|
+
// generic identity function
|
|
51
|
+
var id = function (x) { return x; };
|
|
52
|
+
describe("Task Laws", function () {
|
|
53
|
+
describe("Functor Laws", function () {
|
|
54
|
+
it("identity: map(id) ≅ id", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
55
|
+
var task, mapped, r1, r2;
|
|
56
|
+
return __generator(this, function (_a) {
|
|
57
|
+
switch (_a.label) {
|
|
58
|
+
case 0:
|
|
59
|
+
task = Task.of(42);
|
|
60
|
+
mapped = Task.map(id)(task);
|
|
61
|
+
return [4 /*yield*/, Task.run(task)];
|
|
62
|
+
case 1:
|
|
63
|
+
r1 = _a.sent();
|
|
64
|
+
return [4 /*yield*/, Task.run(mapped)];
|
|
65
|
+
case 2:
|
|
66
|
+
r2 = _a.sent();
|
|
67
|
+
expect(r1).toEqual(r2);
|
|
68
|
+
return [2 /*return*/];
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
}); });
|
|
72
|
+
it("composition: map(g∘f) ≅ map(g)∘map(f)", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
73
|
+
var task, f, g, r1, r2;
|
|
74
|
+
return __generator(this, function (_a) {
|
|
75
|
+
switch (_a.label) {
|
|
76
|
+
case 0:
|
|
77
|
+
task = Task.of(10);
|
|
78
|
+
f = function (n) { return n * 2; };
|
|
79
|
+
g = function (n) { return n + 1; };
|
|
80
|
+
return [4 /*yield*/, Task.run(Task.map(function (x) { return g(f(x)); })(task))];
|
|
81
|
+
case 1:
|
|
82
|
+
r1 = _a.sent();
|
|
83
|
+
return [4 /*yield*/, Task.run(Task.map(g)(Task.map(f)(task)))];
|
|
84
|
+
case 2:
|
|
85
|
+
r2 = _a.sent();
|
|
86
|
+
expect(r1).toEqual(r2);
|
|
87
|
+
return [2 /*return*/];
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
}); });
|
|
91
|
+
});
|
|
92
|
+
describe("Monad Laws", function () {
|
|
93
|
+
it("left identity: chain(f)(of(x)) ≅ f(x)", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
94
|
+
var x, f, r1, r2;
|
|
95
|
+
return __generator(this, function (_a) {
|
|
96
|
+
switch (_a.label) {
|
|
97
|
+
case 0:
|
|
98
|
+
x = 42;
|
|
99
|
+
f = function (n) { return Task.of(n * 2); };
|
|
100
|
+
return [4 /*yield*/, Task.run(Task.chain(f)(Task.of(x)))];
|
|
101
|
+
case 1:
|
|
102
|
+
r1 = _a.sent();
|
|
103
|
+
return [4 /*yield*/, Task.run(f(x))];
|
|
104
|
+
case 2:
|
|
105
|
+
r2 = _a.sent();
|
|
106
|
+
expect(r1).toEqual(r2);
|
|
107
|
+
return [2 /*return*/];
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
}); });
|
|
111
|
+
it("right identity: chain(of)(m) ≅ m", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
112
|
+
var task, chained, r1, r2;
|
|
113
|
+
return __generator(this, function (_a) {
|
|
114
|
+
switch (_a.label) {
|
|
115
|
+
case 0:
|
|
116
|
+
task = Task.of(42);
|
|
117
|
+
chained = Task.chain(Task.of)(task);
|
|
118
|
+
return [4 /*yield*/, Task.run(task)];
|
|
119
|
+
case 1:
|
|
120
|
+
r1 = _a.sent();
|
|
121
|
+
return [4 /*yield*/, Task.run(chained)];
|
|
122
|
+
case 2:
|
|
123
|
+
r2 = _a.sent();
|
|
124
|
+
expect(r1).toEqual(r2);
|
|
125
|
+
return [2 /*return*/];
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
}); });
|
|
129
|
+
it("associativity: chain(g)(chain(f)(m)) ≅ chain(x => chain(g)(f(x)))(m)", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
130
|
+
var task, f, g, r1, r2;
|
|
131
|
+
return __generator(this, function (_a) {
|
|
132
|
+
switch (_a.label) {
|
|
133
|
+
case 0:
|
|
134
|
+
task = Task.of(10);
|
|
135
|
+
f = function (n) { return Task.of(n * 2); };
|
|
136
|
+
g = function (n) { return Task.of(n + 1); };
|
|
137
|
+
return [4 /*yield*/, Task.run(Task.chain(g)(Task.chain(f)(task)))];
|
|
138
|
+
case 1:
|
|
139
|
+
r1 = _a.sent();
|
|
140
|
+
return [4 /*yield*/, Task.run(Task.chain(function (x) { return Task.chain(g)(f(x)); })(task))];
|
|
141
|
+
case 2:
|
|
142
|
+
r2 = _a.sent();
|
|
143
|
+
expect(r1).toEqual(r2);
|
|
144
|
+
return [2 /*return*/];
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
}); });
|
|
148
|
+
});
|
|
149
|
+
describe("Applicative Laws", function () {
|
|
150
|
+
it("identity: ap(of(id))(v) ≅ v", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
151
|
+
var value, identity, r1, r2;
|
|
152
|
+
return __generator(this, function (_a) {
|
|
153
|
+
switch (_a.label) {
|
|
154
|
+
case 0:
|
|
155
|
+
value = Task.of(42);
|
|
156
|
+
identity = Task.of(id);
|
|
157
|
+
return [4 /*yield*/, Task.run(Task.ap(value)(identity))];
|
|
158
|
+
case 1:
|
|
159
|
+
r1 = _a.sent();
|
|
160
|
+
return [4 /*yield*/, Task.run(value)];
|
|
161
|
+
case 2:
|
|
162
|
+
r2 = _a.sent();
|
|
163
|
+
expect(r1).toEqual(r2);
|
|
164
|
+
return [2 /*return*/];
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
}); });
|
|
168
|
+
it("composition: ap(ap(ap(of(compose))(u))(v))(w) ≅ ap(u)(ap(v)(w))", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
169
|
+
var compose, u, v, w, step1, step2, r1, innerAp, outerAp, r2;
|
|
170
|
+
return __generator(this, function (_a) {
|
|
171
|
+
switch (_a.label) {
|
|
172
|
+
case 0:
|
|
173
|
+
compose = function (g) { return function (f) { return function (x) { return g(f(x)); }; }; };
|
|
174
|
+
u = Task.of(function (n) { return n * 2; });
|
|
175
|
+
v = Task.of(function (n) { return n + 10; });
|
|
176
|
+
w = Task.of(5);
|
|
177
|
+
step1 = Task.ap(u)(Task.of(compose));
|
|
178
|
+
step2 = Task.ap(v)(step1);
|
|
179
|
+
return [4 /*yield*/, Task.run(Task.ap(w)(step2))];
|
|
180
|
+
case 1:
|
|
181
|
+
r1 = _a.sent();
|
|
182
|
+
innerAp = Task.ap(w)(v);
|
|
183
|
+
outerAp = Task.ap(innerAp)(u);
|
|
184
|
+
return [4 /*yield*/, Task.run(outerAp)];
|
|
185
|
+
case 2:
|
|
186
|
+
r2 = _a.sent();
|
|
187
|
+
expect(r1).toEqual(r2);
|
|
188
|
+
return [2 /*return*/];
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
}); });
|
|
192
|
+
it("homomorphism: ap(of(x))(of(f)) ≅ of(f(x))", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
193
|
+
var f, x, r1, r2;
|
|
194
|
+
return __generator(this, function (_a) {
|
|
195
|
+
switch (_a.label) {
|
|
196
|
+
case 0:
|
|
197
|
+
f = function (n) { return n * 2; };
|
|
198
|
+
x = 42;
|
|
199
|
+
return [4 /*yield*/, Task.run(Task.ap(Task.of(x))(Task.of(f)))];
|
|
200
|
+
case 1:
|
|
201
|
+
r1 = _a.sent();
|
|
202
|
+
return [4 /*yield*/, Task.run(Task.of(f(x)))];
|
|
203
|
+
case 2:
|
|
204
|
+
r2 = _a.sent();
|
|
205
|
+
expect(r1).toEqual(r2);
|
|
206
|
+
return [2 /*return*/];
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
}); });
|
|
210
|
+
it("interchange: ap(of(y))(u) ≅ ap(u)(of(f => f(y)))", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
211
|
+
var y, u, r1, r2;
|
|
212
|
+
return __generator(this, function (_a) {
|
|
213
|
+
switch (_a.label) {
|
|
214
|
+
case 0:
|
|
215
|
+
y = 42;
|
|
216
|
+
u = Task.of(function (n) { return n * 2; });
|
|
217
|
+
return [4 /*yield*/, Task.run(Task.ap(Task.of(y))(u))];
|
|
218
|
+
case 1:
|
|
219
|
+
r1 = _a.sent();
|
|
220
|
+
return [4 /*yield*/, Task.run(Task.ap(u)(Task.of(function (f) { return f(y); })))];
|
|
221
|
+
case 2:
|
|
222
|
+
r2 = _a.sent();
|
|
223
|
+
expect(r1).toEqual(r2);
|
|
224
|
+
return [2 /*return*/];
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
}); });
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
describe("IO Laws", function () {
|
|
231
|
+
describe("Functor Laws", function () {
|
|
232
|
+
it("identity: map(id) ≅ id", function () {
|
|
233
|
+
var io = IO.of(42);
|
|
234
|
+
var mapped = IO.map(id)(io);
|
|
235
|
+
expect(IO.run(io)).toEqual(IO.run(mapped));
|
|
236
|
+
});
|
|
237
|
+
it("composition: map(g∘f) ≅ map(g)∘map(f)", function () {
|
|
238
|
+
var io = IO.of(10);
|
|
239
|
+
var f = function (n) { return n * 2; };
|
|
240
|
+
var g = function (n) { return n + 1; };
|
|
241
|
+
var r1 = IO.run(IO.map(function (x) { return g(f(x)); })(io));
|
|
242
|
+
var r2 = IO.run(IO.map(g)(IO.map(f)(io)));
|
|
243
|
+
expect(r1).toEqual(r2);
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
describe("Applicative Laws", function () {
|
|
247
|
+
it("identity: ap(of(id))(v) ≅ v", function () {
|
|
248
|
+
var value = IO.of(42);
|
|
249
|
+
var identity = IO.of(id);
|
|
250
|
+
var r1 = IO.run(IO.ap(value)(identity));
|
|
251
|
+
var r2 = IO.run(value);
|
|
252
|
+
expect(r1).toEqual(r2);
|
|
253
|
+
});
|
|
254
|
+
it("composition: ap(ap(ap(of(compose))(u))(v))(w) ≅ ap(u)(ap(v)(w))", function () {
|
|
255
|
+
var compose = function (g) { return function (f) { return function (x) { return g(f(x)); }; }; };
|
|
256
|
+
var u = IO.of(function (n) { return n * 2; });
|
|
257
|
+
var v = IO.of(function (n) { return n + 10; });
|
|
258
|
+
var w = IO.of(5);
|
|
259
|
+
// Left side: compose via lifted compose function
|
|
260
|
+
var step1 = IO.ap(u)(IO.of(compose));
|
|
261
|
+
var step2 = IO.ap(v)(step1);
|
|
262
|
+
var r1 = IO.run(IO.ap(w)(step2));
|
|
263
|
+
// Right side: direct composition
|
|
264
|
+
var innerAp = IO.ap(w)(v);
|
|
265
|
+
var outerAp = IO.ap(innerAp)(u);
|
|
266
|
+
var r2 = IO.run(outerAp);
|
|
267
|
+
expect(r1).toEqual(r2);
|
|
268
|
+
});
|
|
269
|
+
it("homomorphism: ap(of(x))(of(f)) ≅ of(f(x))", function () {
|
|
270
|
+
var f = function (n) { return n * 2; };
|
|
271
|
+
var x = 42;
|
|
272
|
+
var r1 = IO.run(IO.ap(IO.of(x))(IO.of(f)));
|
|
273
|
+
var r2 = IO.run(IO.of(f(x)));
|
|
274
|
+
expect(r1).toEqual(r2);
|
|
275
|
+
});
|
|
276
|
+
it("interchange: ap(of(y))(u) ≅ ap(u)(of(f => f(y)))", function () {
|
|
277
|
+
var y = 42;
|
|
278
|
+
var u = IO.of(function (n) { return n * 2; });
|
|
279
|
+
var r1 = IO.run(IO.ap(IO.of(y))(u));
|
|
280
|
+
var r2 = IO.run(IO.ap(u)(IO.of(function (f) { return f(y); })));
|
|
281
|
+
expect(r1).toEqual(r2);
|
|
282
|
+
});
|
|
283
|
+
});
|
|
284
|
+
describe("Monad Laws", function () {
|
|
285
|
+
it("left identity: chain(f)(of(x)) ≅ f(x)", function () {
|
|
286
|
+
var x = 42;
|
|
287
|
+
var f = function (n) { return IO.of(n * 2); };
|
|
288
|
+
var r1 = IO.run(IO.chain(f)(IO.of(x)));
|
|
289
|
+
var r2 = IO.run(f(x));
|
|
290
|
+
expect(r1).toEqual(r2);
|
|
291
|
+
});
|
|
292
|
+
it("right identity: chain(of)(m) ≅ m", function () {
|
|
293
|
+
var io = IO.of(42);
|
|
294
|
+
var chained = IO.chain(IO.of)(io);
|
|
295
|
+
expect(IO.run(io)).toEqual(IO.run(chained));
|
|
296
|
+
});
|
|
297
|
+
it("associativity: chain(g)(chain(f)(m)) ≅ chain(x => chain(g)(f(x)))(m)", function () {
|
|
298
|
+
var io = IO.of(10);
|
|
299
|
+
var f = function (n) { return IO.of(n * 2); };
|
|
300
|
+
var g = function (n) { return IO.of(n + 1); };
|
|
301
|
+
var r1 = IO.run(IO.chain(g)(IO.chain(f)(io)));
|
|
302
|
+
var r2 = IO.run(IO.chain(function (x) { return IO.chain(g)(f(x)); })(io));
|
|
303
|
+
expect(r1).toEqual(r2);
|
|
304
|
+
});
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
describe("Reader Laws", function () {
|
|
308
|
+
var testEnv = { multiplier: 2, offset: 10 };
|
|
309
|
+
describe("Functor Laws", function () {
|
|
310
|
+
it("identity: map(id) ≅ id", function () {
|
|
311
|
+
var reader = Reader.of(42);
|
|
312
|
+
var mapped = Reader.map(id)(reader);
|
|
313
|
+
expect(Reader.run(testEnv)(reader)).toEqual(Reader.run(testEnv)(mapped));
|
|
314
|
+
});
|
|
315
|
+
it("composition: map(g∘f) ≅ map(g)∘map(f)", function () {
|
|
316
|
+
var reader = Reader.asks(function (env) { return env.multiplier; });
|
|
317
|
+
var f = function (n) { return n * 2; };
|
|
318
|
+
var g = function (n) { return n + 1; };
|
|
319
|
+
var r1 = Reader.run(testEnv)(Reader.map(function (x) { return g(f(x)); })(reader));
|
|
320
|
+
var r2 = Reader.run(testEnv)(Reader.map(g)(Reader.map(f)(reader)));
|
|
321
|
+
expect(r1).toEqual(r2);
|
|
322
|
+
});
|
|
323
|
+
});
|
|
324
|
+
describe("Applicative Laws", function () {
|
|
325
|
+
it("identity: ap(of(id))(v) ≅ v", function () {
|
|
326
|
+
var value = Reader.of(42);
|
|
327
|
+
var identity = Reader.of(id);
|
|
328
|
+
var r1 = Reader.run(testEnv)(Reader.ap(value)(identity));
|
|
329
|
+
var r2 = Reader.run(testEnv)(value);
|
|
330
|
+
expect(r1).toEqual(r2);
|
|
331
|
+
});
|
|
332
|
+
it("composition: ap(ap(ap(of(compose))(u))(v))(w) ≅ ap(u)(ap(v)(w))", function () {
|
|
333
|
+
var compose = function (g) { return function (f) { return function (x) { return g(f(x)); }; }; };
|
|
334
|
+
var u = Reader.of(function (n) { return n * 2; });
|
|
335
|
+
var v = Reader.of(function (n) { return n + 10; });
|
|
336
|
+
var w = Reader.of(5);
|
|
337
|
+
// Left side: compose via lifted compose function
|
|
338
|
+
var composeReader = Reader.of(compose);
|
|
339
|
+
var applyU = Reader.ap(u)(composeReader);
|
|
340
|
+
var applyV = Reader.ap(v)(applyU);
|
|
341
|
+
var r1 = Reader.run(testEnv)(Reader.ap(w)(applyV));
|
|
342
|
+
// Right side: direct composition
|
|
343
|
+
var r2 = Reader.run(testEnv)(Reader.ap(Reader.ap(w)(v))(u));
|
|
344
|
+
expect(r1).toEqual(r2);
|
|
345
|
+
});
|
|
346
|
+
it("homomorphism: ap(of(x))(of(f)) ≅ of(f(x))", function () {
|
|
347
|
+
var f = function (n) { return n * 2; };
|
|
348
|
+
var x = 42;
|
|
349
|
+
var r1 = Reader.run(testEnv)(Reader.ap(Reader.of(x))(Reader.of(f)));
|
|
350
|
+
var r2 = Reader.run(testEnv)(Reader.of(f(x)));
|
|
351
|
+
expect(r1).toEqual(r2);
|
|
352
|
+
});
|
|
353
|
+
it("interchange: ap(of(y))(u) ≅ ap(u)(of(f => f(y)))", function () {
|
|
354
|
+
var y = 42;
|
|
355
|
+
var u = Reader.of(function (n) { return n * 2; });
|
|
356
|
+
var r1 = Reader.run(testEnv)(Reader.ap(Reader.of(y))(u));
|
|
357
|
+
var r2 = Reader.run(testEnv)(Reader.ap(u)(Reader.of(function (f) { return f(y); })));
|
|
358
|
+
expect(r1).toEqual(r2);
|
|
359
|
+
});
|
|
360
|
+
});
|
|
361
|
+
describe("Monad Laws", function () {
|
|
362
|
+
it("left identity: chain(f)(of(x)) ≅ f(x)", function () {
|
|
363
|
+
var x = 42;
|
|
364
|
+
var f = function (n) {
|
|
365
|
+
return Reader.asks(function (env) { return n * env.multiplier; });
|
|
366
|
+
};
|
|
367
|
+
var r1 = Reader.run(testEnv)(Reader.chain(f)(Reader.of(x)));
|
|
368
|
+
var r2 = Reader.run(testEnv)(f(x));
|
|
369
|
+
expect(r1).toEqual(r2);
|
|
370
|
+
});
|
|
371
|
+
it("right identity: chain(of)(m) ≅ m", function () {
|
|
372
|
+
var reader = Reader.asks(function (env) { return env.offset; });
|
|
373
|
+
var chained = Reader.chain(Reader.of)(reader);
|
|
374
|
+
expect(Reader.run(testEnv)(reader)).toEqual(Reader.run(testEnv)(chained));
|
|
375
|
+
});
|
|
376
|
+
it("associativity: chain(g)(chain(f)(m)) ≅ chain(x => chain(g)(f(x)))(m)", function () {
|
|
377
|
+
var reader = Reader.of(10);
|
|
378
|
+
var f = function (n) {
|
|
379
|
+
return Reader.asks(function (env) { return n * env.multiplier; });
|
|
380
|
+
};
|
|
381
|
+
var g = function (n) {
|
|
382
|
+
return Reader.asks(function (env) { return n + env.offset; });
|
|
383
|
+
};
|
|
384
|
+
var r1 = Reader.run(testEnv)(Reader.chain(g)(Reader.chain(f)(reader)));
|
|
385
|
+
var r2 = Reader.run(testEnv)(Reader.chain(function (x) { return Reader.chain(g)(f(x)); })(reader));
|
|
386
|
+
expect(r1).toEqual(r2);
|
|
387
|
+
});
|
|
388
|
+
});
|
|
389
|
+
describe("Reader-specific Laws", function () {
|
|
390
|
+
it("ask law: run(env)(ask) ≅ env", function () {
|
|
391
|
+
var reader = Reader.ask();
|
|
392
|
+
expect(Reader.run(testEnv)(reader)).toEqual(testEnv);
|
|
393
|
+
});
|
|
394
|
+
it("asks law: run(env)(asks(f)) ≅ f(env)", function () {
|
|
395
|
+
var f = function (env) { return env.multiplier * env.offset; };
|
|
396
|
+
var reader = Reader.asks(f);
|
|
397
|
+
expect(Reader.run(testEnv)(reader)).toEqual(f(testEnv));
|
|
398
|
+
});
|
|
399
|
+
it("local law: run(env)(local(f)(r)) ≅ run(f(env))(r)", function () {
|
|
400
|
+
var outerEnv = { inner: testEnv };
|
|
401
|
+
var reader = Reader.asks(function (env) { return env.multiplier; });
|
|
402
|
+
var f = function (outer) { return outer.inner; };
|
|
403
|
+
var r1 = Reader.run(outerEnv)(Reader.local(f)(reader));
|
|
404
|
+
var r2 = Reader.run(f(outerEnv))(reader);
|
|
405
|
+
expect(r1).toEqual(r2);
|
|
406
|
+
});
|
|
407
|
+
});
|
|
408
|
+
});
|
|
409
|
+
describe("Result Laws", function () {
|
|
410
|
+
describe("Functor Laws", function () {
|
|
411
|
+
it("identity: map(id) ≅ id", function () {
|
|
412
|
+
var ok = Result.ok(42);
|
|
413
|
+
var err = Result.err("error");
|
|
414
|
+
expect(Result.map(id)(ok)).toEqual(ok);
|
|
415
|
+
expect(Result.map(id)(err)).toEqual(err);
|
|
416
|
+
});
|
|
417
|
+
it("composition: map(g∘f) ≅ map(g)∘map(f)", function () {
|
|
418
|
+
var result = Result.ok(10);
|
|
419
|
+
var f = function (n) { return n * 2; };
|
|
420
|
+
var g = function (n) { return n + 1; };
|
|
421
|
+
var r1 = Result.map(function (x) { return g(f(x)); })(result);
|
|
422
|
+
var r2 = Result.map(g)(Result.map(f)(result));
|
|
423
|
+
expect(r1).toEqual(r2);
|
|
424
|
+
});
|
|
425
|
+
});
|
|
426
|
+
describe("Applicative Laws", function () {
|
|
427
|
+
it("identity: ap(of(id))(v) ≅ v", function () {
|
|
428
|
+
var value = Result.ok(42);
|
|
429
|
+
var identity = Result.ok(id);
|
|
430
|
+
var r1 = Result.ap(value)(identity);
|
|
431
|
+
var r2 = value;
|
|
432
|
+
expect(r1).toEqual(r2);
|
|
433
|
+
});
|
|
434
|
+
it("composition: ap(ap(ap(of(compose))(u))(v))(w) ≅ ap(u)(ap(v)(w))", function () {
|
|
435
|
+
var compose = function (g) { return function (f) { return function (x) { return g(f(x)); }; }; };
|
|
436
|
+
var u = Result.ok(function (n) { return n * 2; });
|
|
437
|
+
var v = Result.ok(function (n) { return n + 10; });
|
|
438
|
+
var w = Result.ok(5);
|
|
439
|
+
// Left side: compose via lifted compose function
|
|
440
|
+
var step1 = Result.ap(u)(Result.ok(compose));
|
|
441
|
+
var step2 = Result.ap(v)(step1);
|
|
442
|
+
var r1 = Result.ap(w)(step2);
|
|
443
|
+
// Right side: direct composition
|
|
444
|
+
var innerAp = Result.ap(w)(v);
|
|
445
|
+
var outerAp = Result.ap(innerAp)(u);
|
|
446
|
+
var r2 = outerAp;
|
|
447
|
+
expect(r1).toEqual(r2);
|
|
448
|
+
});
|
|
449
|
+
it("homomorphism: ap(of(x))(of(f)) ≅ of(f(x))", function () {
|
|
450
|
+
var f = function (n) { return n * 2; };
|
|
451
|
+
var x = 42;
|
|
452
|
+
var r1 = Result.ap(Result.ok(x))(Result.ok(f));
|
|
453
|
+
var r2 = Result.ok(f(x));
|
|
454
|
+
expect(r1).toEqual(r2);
|
|
455
|
+
});
|
|
456
|
+
it("interchange: ap(of(y))(u) ≅ ap(u)(of(f => f(y)))", function () {
|
|
457
|
+
var y = 42;
|
|
458
|
+
var u = Result.ok(function (n) { return n * 2; });
|
|
459
|
+
var r1 = Result.ap(Result.ok(y))(u);
|
|
460
|
+
var r2 = Result.ap(u)(Result.ok(function (f) { return f(y); }));
|
|
461
|
+
expect(r1).toEqual(r2);
|
|
462
|
+
});
|
|
463
|
+
});
|
|
464
|
+
describe("Monad Laws", function () {
|
|
465
|
+
it("left identity: chain(f)(of(x)) ≅ f(x)", function () {
|
|
466
|
+
var x = 42;
|
|
467
|
+
var f = function (n) {
|
|
468
|
+
return n > 0 ? Result.ok(n * 2) : Result.err("negative");
|
|
469
|
+
};
|
|
470
|
+
var r1 = Result.flatMap(f)(Result.ok(x));
|
|
471
|
+
var r2 = f(x);
|
|
472
|
+
expect(r1).toEqual(r2);
|
|
473
|
+
});
|
|
474
|
+
it("right identity: chain(of)(m) ≅ m", function () {
|
|
475
|
+
var result = Result.ok(42);
|
|
476
|
+
var chained = Result.flatMap(Result.ok)(result);
|
|
477
|
+
expect(result).toEqual(chained);
|
|
478
|
+
});
|
|
479
|
+
it("associativity: chain(g)(chain(f)(m)) ≅ chain(x => chain(g)(f(x)))(m)", function () {
|
|
480
|
+
var result = Result.ok(10);
|
|
481
|
+
var f = function (n) { return Result.ok(n * 2); };
|
|
482
|
+
var g = function (n) { return Result.ok(n + 1); };
|
|
483
|
+
var r1 = Result.flatMap(g)(Result.flatMap(f)(result));
|
|
484
|
+
var r2 = Result.flatMap(function (x) { return Result.flatMap(g)(f(x)); })(result);
|
|
485
|
+
expect(r1).toEqual(r2);
|
|
486
|
+
});
|
|
487
|
+
});
|
|
488
|
+
});
|
|
489
|
+
describe("Option Laws", function () {
|
|
490
|
+
describe("Functor Laws", function () {
|
|
491
|
+
it("identity: map(id) ≅ id", function () {
|
|
492
|
+
var someVal = some(42);
|
|
493
|
+
var noneVal = none();
|
|
494
|
+
expect(Option.map(id)(someVal)).toEqual(someVal);
|
|
495
|
+
expect(Option.map(id)(noneVal)).toEqual(noneVal);
|
|
496
|
+
});
|
|
497
|
+
it("composition: map(g∘f) ≅ map(g)∘map(f)", function () {
|
|
498
|
+
var option = some(10);
|
|
499
|
+
var f = function (n) { return n * 2; };
|
|
500
|
+
var g = function (n) { return n + 1; };
|
|
501
|
+
var r1 = Option.map(function (x) { return g(f(x)); })(option);
|
|
502
|
+
var r2 = Option.map(g)(Option.map(f)(option));
|
|
503
|
+
expect(r1).toEqual(r2);
|
|
504
|
+
});
|
|
505
|
+
});
|
|
506
|
+
describe("Applicative Laws", function () {
|
|
507
|
+
it("identity: ap(of(id))(v) ≅ v", function () {
|
|
508
|
+
var value = some(42);
|
|
509
|
+
var identity = some(id);
|
|
510
|
+
var r1 = Option.ap(value)(identity);
|
|
511
|
+
var r2 = value;
|
|
512
|
+
expect(r1).toEqual(r2);
|
|
513
|
+
});
|
|
514
|
+
it("composition: ap(ap(ap(of(compose))(u))(v))(w) ≅ ap(u)(ap(v)(w))", function () {
|
|
515
|
+
var compose = function (g) { return function (f) { return function (x) { return g(f(x)); }; }; };
|
|
516
|
+
var u = some(function (n) { return n * 2; });
|
|
517
|
+
var v = some(function (n) { return n + 10; });
|
|
518
|
+
var w = some(5);
|
|
519
|
+
// Left side: compose via lifted compose function
|
|
520
|
+
var step1 = Option.ap(u)(some(compose));
|
|
521
|
+
var step2 = Option.ap(v)(step1);
|
|
522
|
+
var r1 = Option.ap(w)(step2);
|
|
523
|
+
// Right side: direct composition
|
|
524
|
+
var innerAp = Option.ap(w)(v);
|
|
525
|
+
var outerAp = Option.ap(innerAp)(u);
|
|
526
|
+
var r2 = outerAp;
|
|
527
|
+
expect(r1).toEqual(r2);
|
|
528
|
+
});
|
|
529
|
+
it("homomorphism: ap(of(x))(of(f)) ≅ of(f(x))", function () {
|
|
530
|
+
var f = function (n) { return n * 2; };
|
|
531
|
+
var x = 42;
|
|
532
|
+
var r1 = Option.ap(some(x))(some(f));
|
|
533
|
+
var r2 = some(f(x));
|
|
534
|
+
expect(r1).toEqual(r2);
|
|
535
|
+
});
|
|
536
|
+
it("interchange: ap(of(y))(u) ≅ ap(u)(of(f => f(y)))", function () {
|
|
537
|
+
var y = 42;
|
|
538
|
+
var u = some(function (n) { return n * 2; });
|
|
539
|
+
var r1 = Option.ap(some(y))(u);
|
|
540
|
+
var r2 = Option.ap(u)(some(function (f) { return f(y); }));
|
|
541
|
+
expect(r1).toEqual(r2);
|
|
542
|
+
});
|
|
543
|
+
});
|
|
544
|
+
describe("Monad Laws", function () {
|
|
545
|
+
it("left identity: chain(f)(of(x)) ≅ f(x)", function () {
|
|
546
|
+
var x = 42;
|
|
547
|
+
var f = function (n) { return (n > 0 ? some(n * 2) : none()); };
|
|
548
|
+
var r1 = Option.flatMap(f)(some(x));
|
|
549
|
+
var r2 = f(x);
|
|
550
|
+
expect(r1).toEqual(r2);
|
|
551
|
+
});
|
|
552
|
+
it("right identity: chain(of)(m) ≅ m", function () {
|
|
553
|
+
var option = some(42);
|
|
554
|
+
var chained = Option.flatMap(some)(option);
|
|
555
|
+
expect(option).toEqual(chained);
|
|
556
|
+
});
|
|
557
|
+
it("associativity: chain(g)(chain(f)(m)) ≅ chain(x => chain(g)(f(x)))(m)", function () {
|
|
558
|
+
var option = some(10);
|
|
559
|
+
var f = function (n) { return some(n * 2); };
|
|
560
|
+
var g = function (n) { return some(n + 1); };
|
|
561
|
+
var r1 = Option.flatMap(g)(Option.flatMap(f)(option));
|
|
562
|
+
var r2 = Option.flatMap(function (x) { return Option.flatMap(g)(f(x)); })(option);
|
|
563
|
+
expect(r1).toEqual(r2);
|
|
564
|
+
});
|
|
565
|
+
});
|
|
566
|
+
});
|
|
567
|
+
describe("Cross-type Law Consistency", function () {
|
|
568
|
+
it("all types should handle identity consistently", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
569
|
+
var value, _a;
|
|
570
|
+
return __generator(this, function (_b) {
|
|
571
|
+
switch (_b.label) {
|
|
572
|
+
case 0:
|
|
573
|
+
value = 42;
|
|
574
|
+
// all should preserve the value through identity
|
|
575
|
+
_a = expect;
|
|
576
|
+
return [4 /*yield*/, Task.run(Task.map(id)(Task.of(value)))];
|
|
577
|
+
case 1:
|
|
578
|
+
// all should preserve the value through identity
|
|
579
|
+
_a.apply(void 0, [_b.sent()]).toBe(value);
|
|
580
|
+
expect(IO.run(IO.map(id)(IO.of(value)))).toBe(value);
|
|
581
|
+
expect(Reader.run({})(Reader.map(id)(Reader.of(value)))).toBe(value);
|
|
582
|
+
expect(Result.map(id)(Result.ok(value))).toEqual(Result.ok(value));
|
|
583
|
+
expect(Option.map(id)(some(value))).toEqual(some(value));
|
|
584
|
+
return [2 /*return*/];
|
|
585
|
+
}
|
|
586
|
+
});
|
|
587
|
+
}); });
|
|
588
|
+
it("all types should handle composition consistently", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
589
|
+
var f, g, compose, value, expected, _a;
|
|
590
|
+
return __generator(this, function (_b) {
|
|
591
|
+
switch (_b.label) {
|
|
592
|
+
case 0:
|
|
593
|
+
f = function (n) { return n * 2; };
|
|
594
|
+
g = function (n) { return n + 1; };
|
|
595
|
+
compose = function (x) { return g(f(x)); };
|
|
596
|
+
value = 10;
|
|
597
|
+
expected = 21;
|
|
598
|
+
// all should produce the same result
|
|
599
|
+
_a = expect;
|
|
600
|
+
return [4 /*yield*/, Task.run(Task.map(compose)(Task.of(value)))];
|
|
601
|
+
case 1:
|
|
602
|
+
// all should produce the same result
|
|
603
|
+
_a.apply(void 0, [_b.sent()]).toBe(expected);
|
|
604
|
+
expect(IO.run(IO.map(compose)(IO.of(value)))).toBe(expected);
|
|
605
|
+
expect(Reader.run({})(Reader.map(compose)(Reader.of(value)))).toBe(expected);
|
|
606
|
+
expect(Result.map(compose)(Result.ok(value))).toEqual(Result.ok(expected));
|
|
607
|
+
expect(Option.map(compose)(some(value))).toEqual(some(expected));
|
|
608
|
+
return [2 /*return*/];
|
|
609
|
+
}
|
|
610
|
+
});
|
|
611
|
+
}); });
|
|
612
|
+
});
|
|
613
|
+
});
|
|
614
|
+
//# sourceMappingURL=laws.test.mjs.map
|