@satoshibits/functional 1.0.3 → 1.1.0

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.
@@ -0,0 +1,431 @@
1
+ /**
2
+ * @module reader
3
+ * @description Reader represents a computation with access to a shared environment/context.
4
+ * The Reader monad provides a way to compose functions that all depend on some shared
5
+ * configuration or dependency injection context, without having to pass it explicitly
6
+ * through every function call.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * import { Reader } from './reader.mts';
11
+ *
12
+ * // basic usage
13
+ * type Config = { apiUrl: string; timeout: number };
14
+ *
15
+ * const getApiUrl: Reader<Config, string> = config => config.apiUrl;
16
+ * const getTimeout: Reader<Config, number> = config => config.timeout;
17
+ *
18
+ * // composing readers
19
+ * const buildRequest = Reader.chain((url: string) =>
20
+ * Reader.map((timeout: number) => ({ url, timeout }))(getTimeout)
21
+ * )(getApiUrl);
22
+ *
23
+ * // running readers
24
+ * const config: Config = { apiUrl: 'https://api.example.com', timeout: 5000 };
25
+ * const request = Reader.run(config)(buildRequest);
26
+ * // => { url: 'https://api.example.com', timeout: 5000 }
27
+ * ```
28
+ *
29
+ * @category Core
30
+ * @since 2025-09-18
31
+ */
32
+ /**
33
+ * Reader type representing a function from environment to a value.
34
+ * @description A Reader is a function that takes an environment/dependency
35
+ * and returns a value. This allows for dependency injection and configuration
36
+ * passing through a computation pipeline.
37
+ *
38
+ * @template R - The type of the environment/dependencies
39
+ * @template A - The type of the value the reader produces
40
+ *
41
+ * @category Types
42
+ * @example
43
+ * ```typescript
44
+ * // Simple reader
45
+ * type Config = { apiKey: string };
46
+ * const getApiKey: Reader<Config, string> = config => config.apiKey;
47
+ *
48
+ * // Reader with computation
49
+ * type Env = { multiplier: number };
50
+ * const double: Reader<Env, number> = env => 10 * env.multiplier;
51
+ * ```
52
+ *
53
+ * @since 2025-09-18
54
+ */
55
+ export type Reader<R, A> = (deps: R) => A;
56
+ /**
57
+ * Reader utility functions for working with Reader types.
58
+ * @description Provides a functional API for creating, transforming, and composing Readers.
59
+ * All functions are curried to support functional composition and partial application.
60
+ *
61
+ * @category Utilities
62
+ * @since 2025-09-18
63
+ */
64
+ export declare const Reader: {
65
+ /**
66
+ * Creates a Reader that returns the given value, ignoring the environment.
67
+ * @description Factory function for creating Readers from values. The resulting
68
+ * Reader will always return the provided value regardless of the environment.
69
+ *
70
+ * @template R - The type of the environment
71
+ * @template A - The type of the value
72
+ * @param {A} value - The value to wrap in a Reader
73
+ * @returns {Reader<R, A>} A Reader that returns the value
74
+ *
75
+ * @category Constructors
76
+ * @example
77
+ * ```typescript
78
+ * const reader = Reader.of<Config, number>(42);
79
+ * Reader.run(config)(reader); // => 42
80
+ *
81
+ * // Useful for starting chains
82
+ * const result = Reader.run(config)(
83
+ * Reader.chain((n: number) => Reader.of<Config, number>(n * 2))(
84
+ * Reader.of<Config, number>(21)
85
+ * )
86
+ * ); // => 42
87
+ * ```
88
+ *
89
+ * @since 2025-09-18
90
+ */
91
+ of: <R, A>(value: A) => Reader<R, A>;
92
+ /**
93
+ * Gets the current environment.
94
+ * @description Returns a Reader that provides access to the entire environment.
95
+ * This is the identity Reader for the environment type.
96
+ *
97
+ * @template R - The type of the environment
98
+ * @returns {Reader<R, R>} A Reader that returns the environment
99
+ *
100
+ * @category Environment
101
+ * @example
102
+ * ```typescript
103
+ * type Config = { port: number; host: string };
104
+ * const config: Config = { port: 3000, host: 'localhost' };
105
+ *
106
+ * const getConfig = Reader.ask<Config>();
107
+ * Reader.run(config)(getConfig); // => { port: 3000, host: 'localhost' }
108
+ * ```
109
+ *
110
+ * @since 2025-09-18
111
+ */
112
+ ask: <R>() => Reader<R, R>;
113
+ /**
114
+ * Gets a value derived from the environment.
115
+ * @description Projects a value from the environment using a selector function.
116
+ * Useful for extracting specific parts of the environment.
117
+ *
118
+ * @template R - The type of the environment
119
+ * @template A - The type of the extracted value
120
+ * @param {function(R): A} f - Function to extract value from environment
121
+ * @returns {Reader<R, A>} A Reader that returns the extracted value
122
+ *
123
+ * @category Environment
124
+ * @example
125
+ * ```typescript
126
+ * type Config = { db: { host: string; port: number } };
127
+ *
128
+ * const getDbHost = Reader.asks<Config, string>(config => config.db.host);
129
+ * const config: Config = { db: { host: 'localhost', port: 5432 } };
130
+ * Reader.run(config)(getDbHost); // => 'localhost'
131
+ * ```
132
+ *
133
+ * @since 2025-09-18
134
+ */
135
+ asks: <R, A>(f: (deps: R) => A) => Reader<R, A>;
136
+ /**
137
+ * Transforms the value inside a Reader using the given function.
138
+ * @description Applies a pure function to the value produced by a Reader,
139
+ * creating a new Reader with the transformed value. This is the functor
140
+ * map operation for Reader types.
141
+ *
142
+ * @template R - The environment type
143
+ * @template A - The input type
144
+ * @template B - The output type
145
+ * @param {function(A): B} f - Function to transform the value
146
+ * @returns {function(Reader<R, A>): Reader<R, B>} A function that transforms Readers
147
+ *
148
+ * @category Transformations
149
+ * @example
150
+ * ```typescript
151
+ * type Config = { multiplier: number };
152
+ * const getValue: Reader<Config, number> = config => 10 * config.multiplier;
153
+ *
154
+ * const double = Reader.map((n: number) => n * 2);
155
+ * const doubled = double(getValue);
156
+ *
157
+ * const config: Config = { multiplier: 3 };
158
+ * Reader.run(config)(doubled); // => 60
159
+ * ```
160
+ *
161
+ * @since 2025-09-18
162
+ */
163
+ map: <R, A, B>(f: (value: A) => B) => (reader: Reader<R, A>) => Reader<R, B>;
164
+ /**
165
+ * Chains Reader-returning operations.
166
+ * @description Sequences two Readers where the second depends on the result
167
+ * of the first. This is the monadic bind operation for Reader types.
168
+ *
169
+ * @template R - The environment type
170
+ * @template A - The input type
171
+ * @template B - The output type
172
+ * @param {function(A): Reader<R, B>} f - Function that returns a new Reader
173
+ * @returns {function(Reader<R, A>): Reader<R, B>} A function that chains Readers
174
+ *
175
+ * @category Combinators
176
+ * @example
177
+ * ```typescript
178
+ * type Config = { baseUrl: string; apiKey: string };
179
+ *
180
+ * const getBaseUrl: Reader<Config, string> = config => config.baseUrl;
181
+ * const buildEndpoint = (base: string): Reader<Config, string> =>
182
+ * config => `${base}/api?key=${config.apiKey}`;
183
+ *
184
+ * const getEndpoint = Reader.chain(buildEndpoint)(getBaseUrl);
185
+ *
186
+ * const config: Config = { baseUrl: 'https://api.com', apiKey: 'secret' };
187
+ * Reader.run(config)(getEndpoint); // => 'https://api.com/api?key=secret'
188
+ * ```
189
+ *
190
+ * @since 2025-09-18
191
+ */
192
+ chain: <R, A, B>(f: (value: A) => Reader<R, B>) => (reader: Reader<R, A>) => Reader<R, B>;
193
+ /**
194
+ * Alias for chain to match fp-ts naming.
195
+ * @description See {@link chain} for details.
196
+ *
197
+ * @category Combinators
198
+ * @since 2025-09-18
199
+ */
200
+ flatMap: <R, A, B>(f: (value: A) => Reader<R, B>) => (reader: Reader<R, A>) => Reader<R, B>;
201
+ /**
202
+ * Applies a Reader of a function to a Reader of a value.
203
+ * @description Enables applying functions wrapped in Readers to values wrapped
204
+ * in Readers. This is the applicative apply operation for Reader types.
205
+ *
206
+ * @template R - The environment type
207
+ * @template A - The input type
208
+ * @template B - The output type
209
+ * @param {Reader<R, A>} readerValue - Reader containing a value
210
+ * @returns {function(Reader<R, function(A): B>): Reader<R, B>} A function that applies Reader functions
211
+ *
212
+ * @category Combinators
213
+ * @example
214
+ * ```typescript
215
+ * type Config = { x: number; y: number };
216
+ *
217
+ * const add = (a: number) => (b: number) => a + b;
218
+ * const getX: Reader<Config, number> = config => config.x;
219
+ * const getY: Reader<Config, number> = config => config.y;
220
+ *
221
+ * const sum = Reader.ap(getY)(
222
+ * Reader.map(add)(getX)
223
+ * );
224
+ *
225
+ * const config: Config = { x: 5, y: 3 };
226
+ * Reader.run(config)(sum); // => 8
227
+ * ```
228
+ *
229
+ * @since 2025-09-18
230
+ */
231
+ ap: <R, A, B>(readerValue: Reader<R, A>) => (readerFn: Reader<R, (a: A) => B>) => Reader<R, B>;
232
+ /**
233
+ * Runs a Reader with the given environment.
234
+ * @description Executes a Reader by providing it with the required environment,
235
+ * returning the computed value.
236
+ *
237
+ * @template R - The type of the environment
238
+ * @template A - The type of the value
239
+ * @param {R} deps - The environment to provide
240
+ * @returns {function(Reader<R, A>): A} A function that runs Readers
241
+ *
242
+ * @category Execution
243
+ * @example
244
+ * ```typescript
245
+ * type Config = { name: string };
246
+ * const getName: Reader<Config, string> = config => config.name;
247
+ *
248
+ * const config: Config = { name: 'Alice' };
249
+ * const name = Reader.run(config)(getName); // => 'Alice'
250
+ * ```
251
+ *
252
+ * @since 2025-09-18
253
+ */
254
+ run: <R>(deps: R) => <A>(reader: Reader<R, A>) => A;
255
+ /**
256
+ * Modifies the environment before running a Reader.
257
+ * @description Transforms the environment using a function before passing it
258
+ * to the Reader. This is contravariant mapping on the environment.
259
+ *
260
+ * @template R - The new environment type
261
+ * @template S - The original environment type
262
+ * @param {function(R): S} f - Function to transform the environment
263
+ * @returns {function(Reader<S, A>): Reader<R, A>} A function that adapts Readers
264
+ *
265
+ * @category Transformations
266
+ * @example
267
+ * ```typescript
268
+ * type AppConfig = { db: DbConfig; api: ApiConfig };
269
+ * type DbConfig = { host: string; port: number };
270
+ *
271
+ * const getDbHost: Reader<DbConfig, string> = config => config.host;
272
+ * const getAppDbHost = Reader.local<AppConfig, DbConfig>(
273
+ * app => app.db
274
+ * )(getDbHost);
275
+ *
276
+ * const appConfig: AppConfig = {
277
+ * db: { host: 'localhost', port: 5432 },
278
+ * api: { url: 'https://api.com' }
279
+ * };
280
+ * Reader.run(appConfig)(getAppDbHost); // => 'localhost'
281
+ * ```
282
+ *
283
+ * @since 2025-09-18
284
+ */
285
+ local: <R, S>(f: (deps: R) => S) => <A>(reader: Reader<S, A>) => Reader<R, A>;
286
+ /**
287
+ * Converts an array of Readers into a Reader of an array.
288
+ * @description Sequences multiple Readers, collecting their results into an array.
289
+ *
290
+ * @template R - The environment type
291
+ * @template A - The type of values in the Readers
292
+ * @param {Reader<R, A>[]} readers - Array of Readers to sequence
293
+ * @returns {Reader<R, A[]>} A Reader containing an array of results
294
+ *
295
+ * @category Combinators
296
+ * @example
297
+ * ```typescript
298
+ * type Config = { x: number; y: number; z: number };
299
+ *
300
+ * const readers = [
301
+ * (c: Config) => c.x,
302
+ * (c: Config) => c.y,
303
+ * (c: Config) => c.z
304
+ * ];
305
+ * const combined = Reader.sequence(readers);
306
+ *
307
+ * const config: Config = { x: 1, y: 2, z: 3 };
308
+ * Reader.run(config)(combined); // => [1, 2, 3]
309
+ * ```
310
+ *
311
+ * @since 2025-09-18
312
+ */
313
+ sequence: <R, A>(readers: Reader<R, A>[]) => Reader<R, A[]>;
314
+ /**
315
+ * Maps a function returning a Reader over an array and sequences the results.
316
+ * @description Applies a Reader-returning function to each element of an array
317
+ * and collects all results.
318
+ *
319
+ * @template R - The environment type
320
+ * @template A - The input type
321
+ * @template B - The output type
322
+ * @param {function(A): Reader<R, B>} f - Function that returns a Reader
323
+ * @returns {function(A[]): Reader<R, B[]>} A function that traverses arrays with Readers
324
+ *
325
+ * @category Combinators
326
+ * @example
327
+ * ```typescript
328
+ * type Config = { multiplier: number };
329
+ *
330
+ * const multiplyBy = (n: number): Reader<Config, number> =>
331
+ * config => n * config.multiplier;
332
+ *
333
+ * const multiplyAll = Reader.traverse(multiplyBy);
334
+ * const results = multiplyAll([1, 2, 3]);
335
+ *
336
+ * const config: Config = { multiplier: 10 };
337
+ * Reader.run(config)(results); // => [10, 20, 30]
338
+ * ```
339
+ *
340
+ * @since 2025-09-18
341
+ */
342
+ traverse: <R, A, B>(f: (a: A) => Reader<R, B>) => (as: A[]) => Reader<R, B[]>;
343
+ /**
344
+ * Combines the results of a tuple of Readers into a Reader of a tuple.
345
+ * @description Takes multiple Readers and returns a Reader containing a tuple
346
+ * of their results.
347
+ *
348
+ * @template R - The environment type
349
+ * @template T - Tuple type of Readers
350
+ * @param {...T} readers - Readers to combine
351
+ * @returns {Reader<R, { [K in keyof T]: T[K] extends Reader<R, infer U> ? U : never }>} Reader of tuple
352
+ *
353
+ * @category Combinators
354
+ * @example
355
+ * ```typescript
356
+ * type Config = { name: string; age: number; active: boolean };
357
+ *
358
+ * const getName: Reader<Config, string> = c => c.name;
359
+ * const getAge: Reader<Config, number> = c => c.age;
360
+ * const getActive: Reader<Config, boolean> = c => c.active;
361
+ *
362
+ * const combined = Reader.sequenceT(getName, getAge, getActive);
363
+ *
364
+ * const config: Config = { name: 'Alice', age: 30, active: true };
365
+ * Reader.run(config)(combined); // => ['Alice', 30, true]
366
+ * ```
367
+ *
368
+ * @since 2025-09-18
369
+ */
370
+ sequenceT: <R, T extends readonly unknown[]>(...readers: { [K in keyof T]: Reader<R, T[K]>; }) => Reader<R, T>;
371
+ /**
372
+ * Combines the results of a record of Readers into a Reader of a record.
373
+ * @description Takes an object with Reader values and returns a Reader containing
374
+ * an object with the results.
375
+ *
376
+ * @template R - The environment type
377
+ * @template S - Record type with Reader values
378
+ * @param {S} readers - Record of Readers to combine
379
+ * @returns {Reader<R, { [K in keyof S]: S[K] extends Reader<R, infer U> ? U : never }>} Reader of record
380
+ *
381
+ * @category Combinators
382
+ * @example
383
+ * ```typescript
384
+ * type Config = { user: string; host: string; port: number };
385
+ *
386
+ * const readers = {
387
+ * username: (c: Config) => c.user,
388
+ * server: (c: Config) => c.host,
389
+ * portNumber: (c: Config) => c.port
390
+ * };
391
+ *
392
+ * const combined = Reader.sequenceS(readers);
393
+ *
394
+ * const config: Config = { user: 'admin', host: 'localhost', port: 3000 };
395
+ * Reader.run(config)(combined);
396
+ * // => { username: 'admin', server: 'localhost', portNumber: 3000 }
397
+ * ```
398
+ *
399
+ * @since 2025-09-18
400
+ */
401
+ sequenceS: <R, S>(readers: { [K in keyof S]: Reader<R, S[K]>; }) => Reader<R, S>;
402
+ /**
403
+ * Executes a Reader for its side effects, discarding the result.
404
+ * @description Runs a Reader-returning function but preserves the original value.
405
+ * Useful for logging or other side effects where the result isn't needed.
406
+ *
407
+ * @template R - The environment type
408
+ * @template A - The type of the value
409
+ * @param {function(A): Reader<R, any>} f - Function that returns a Reader (result discarded)
410
+ * @returns {function(Reader<R, A>): Reader<R, A>} A function that executes side effects
411
+ *
412
+ * @category Combinators
413
+ * @example
414
+ * ```typescript
415
+ * type Config = { logger: (msg: string) => void };
416
+ *
417
+ * const log = (msg: string): Reader<Config, void> =>
418
+ * config => config.logger(msg);
419
+ *
420
+ * const getValue: Reader<Config, number> = () => 42;
421
+ * const logged = Reader.chainFirst((n: number) => log(`Got: ${n}`))(getValue);
422
+ *
423
+ * const config: Config = { logger: console.log };
424
+ * Reader.run(config)(logged); // logs "Got: 42", returns 42
425
+ * ```
426
+ *
427
+ * @since 2025-09-18
428
+ */
429
+ chainFirst: <R, A>(f: (a: A) => Reader<R, unknown>) => (reader: Reader<R, A>) => Reader<R, A>;
430
+ };
431
+ //# sourceMappingURL=reader.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reader.d.mts","sourceRoot":"","sources":["../src/reader.mts"],"names":[],"mappings":"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"}