effect 3.11.8 → 3.11.9
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/dist/cjs/Effect.js +1685 -293
- package/dist/cjs/Effect.js.map +1 -1
- package/dist/cjs/Option.js +1 -1
- package/dist/cjs/Schema.js +57 -40
- package/dist/cjs/Schema.js.map +1 -1
- package/dist/cjs/SchemaAST.js +44 -42
- package/dist/cjs/SchemaAST.js.map +1 -1
- package/dist/cjs/internal/core-effect.js +3 -3
- package/dist/cjs/internal/core-effect.js.map +1 -1
- package/dist/cjs/internal/fiberRuntime.js +4 -4
- package/dist/cjs/internal/fiberRuntime.js.map +1 -1
- package/dist/cjs/internal/version.js +1 -1
- package/dist/dts/Effect.d.ts +12053 -8146
- package/dist/dts/Effect.d.ts.map +1 -1
- package/dist/dts/Option.d.ts +1 -1
- package/dist/dts/Schema.d.ts +1 -1
- package/dist/dts/Schema.d.ts.map +1 -1
- package/dist/dts/SchemaAST.d.ts +9 -1
- package/dist/dts/SchemaAST.d.ts.map +1 -1
- package/dist/dts/internal/core-effect.d.ts.map +1 -1
- package/dist/esm/Effect.js +1734 -294
- package/dist/esm/Effect.js.map +1 -1
- package/dist/esm/Option.js +1 -1
- package/dist/esm/Schema.js +57 -40
- package/dist/esm/Schema.js.map +1 -1
- package/dist/esm/SchemaAST.js +43 -41
- package/dist/esm/SchemaAST.js.map +1 -1
- package/dist/esm/internal/core-effect.js +3 -3
- package/dist/esm/internal/core-effect.js.map +1 -1
- package/dist/esm/internal/fiberRuntime.js +4 -4
- package/dist/esm/internal/fiberRuntime.js.map +1 -1
- package/dist/esm/internal/version.js +1 -1
- package/package.json +1 -1
- package/src/Effect.ts +7191 -3280
- package/src/Option.ts +1 -1
- package/src/Schema.ts +57 -42
- package/src/SchemaAST.ts +52 -44
- package/src/internal/core-effect.ts +11 -8
- package/src/internal/fiberRuntime.ts +14 -14
- package/src/internal/version.ts +1 -1
package/dist/esm/Effect.js
CHANGED
|
@@ -20,22 +20,50 @@ import { internalCall, isGeneratorFunction } from "./Utils.js";
|
|
|
20
20
|
*/
|
|
21
21
|
export const EffectTypeId = core.EffectTypeId;
|
|
22
22
|
/**
|
|
23
|
-
*
|
|
24
|
-
*
|
|
23
|
+
* Checks if a given value is an `Effect` value.
|
|
24
|
+
*
|
|
25
|
+
* **When to Use**
|
|
25
26
|
*
|
|
26
27
|
* This function can be useful for checking the type of a value before
|
|
27
28
|
* attempting to operate on it as an `Effect` value. For example, you could use
|
|
28
|
-
* `isEffect` to check the type of a value before using it as an argument
|
|
29
|
-
* function that expects an `Effect` value.
|
|
29
|
+
* `Effect.isEffect` to check the type of a value before using it as an argument
|
|
30
|
+
* to a function that expects an `Effect` value.
|
|
30
31
|
*
|
|
31
32
|
* @since 2.0.0
|
|
32
|
-
* @category
|
|
33
|
+
* @category Guards
|
|
33
34
|
*/
|
|
34
35
|
export const isEffect = core.isEffect;
|
|
35
36
|
/**
|
|
36
|
-
* Returns an effect that caches its result for a specified
|
|
37
|
-
*
|
|
38
|
-
*
|
|
37
|
+
* Returns an effect that caches its result for a specified `Duration`,
|
|
38
|
+
* known as "timeToLive" (TTL).
|
|
39
|
+
*
|
|
40
|
+
* **Details**
|
|
41
|
+
*
|
|
42
|
+
* This function is used to cache the result of an effect for a specified amount
|
|
43
|
+
* of time. This means that the first time the effect is evaluated, its result
|
|
44
|
+
* is computed and stored.
|
|
45
|
+
*
|
|
46
|
+
* If the effect is evaluated again within the specified `timeToLive`, the
|
|
47
|
+
* cached result will be used, avoiding recomputation.
|
|
48
|
+
*
|
|
49
|
+
* After the specified duration has passed, the cache expires, and the effect
|
|
50
|
+
* will be recomputed upon the next evaluation.
|
|
51
|
+
*
|
|
52
|
+
* **When to Use**
|
|
53
|
+
*
|
|
54
|
+
* Use this function when you have an effect that involves costly operations or
|
|
55
|
+
* computations, and you want to avoid repeating them within a short time frame.
|
|
56
|
+
*
|
|
57
|
+
* It's ideal for scenarios where the result of an effect doesn't change
|
|
58
|
+
* frequently and can be reused for a specified duration.
|
|
59
|
+
*
|
|
60
|
+
* By caching the result, you can improve efficiency and reduce unnecessary
|
|
61
|
+
* computations, especially in performance-critical applications.
|
|
62
|
+
*
|
|
63
|
+
* @see {@link cached} for a similar function that caches the result
|
|
64
|
+
* indefinitely.
|
|
65
|
+
* @see {@link cachedInvalidateWithTTL} for a similar function that includes an
|
|
66
|
+
* additional effect for manually invalidating the cached value.
|
|
39
67
|
*
|
|
40
68
|
* @example
|
|
41
69
|
* ```ts
|
|
@@ -73,9 +101,36 @@ export const isEffect = core.isEffect;
|
|
|
73
101
|
*/
|
|
74
102
|
export const cachedWithTTL = circular.cached;
|
|
75
103
|
/**
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
104
|
+
* Caches an effect's result for a specified duration and allows manual
|
|
105
|
+
* invalidation before expiration.
|
|
106
|
+
*
|
|
107
|
+
* **Details**
|
|
108
|
+
*
|
|
109
|
+
* This function behaves similarly to {@link cachedWithTTL} by caching the
|
|
110
|
+
* result of an effect for a specified period of time. However, it introduces an
|
|
111
|
+
* additional feature: it provides an effect that allows you to manually
|
|
112
|
+
* invalidate the cached result before it naturally expires.
|
|
113
|
+
*
|
|
114
|
+
* This gives you more control over the cache, allowing you to refresh the
|
|
115
|
+
* result when needed, even if the original cache has not yet expired.
|
|
116
|
+
*
|
|
117
|
+
* Once the cache is invalidated, the next time the effect is evaluated, the
|
|
118
|
+
* result will be recomputed, and the cache will be refreshed.
|
|
119
|
+
*
|
|
120
|
+
* **When to Use**
|
|
121
|
+
*
|
|
122
|
+
* Use this function when you have an effect whose result needs to be cached for
|
|
123
|
+
* a certain period, but you also want the option to refresh the cache manually
|
|
124
|
+
* before the expiration time.
|
|
125
|
+
*
|
|
126
|
+
* This is useful when you need to ensure that the cached data remains valid for
|
|
127
|
+
* a certain period but still want to invalidate it if the underlying data
|
|
128
|
+
* changes or if you want to force a recomputation.
|
|
129
|
+
*
|
|
130
|
+
* @see {@link cached} for a similar function that caches the result
|
|
131
|
+
* indefinitely.
|
|
132
|
+
* @see {@link cachedWithTTL} for a similar function that caches the result for
|
|
133
|
+
* a specified duration but does not include an effect for manual invalidation.
|
|
79
134
|
*
|
|
80
135
|
* @example
|
|
81
136
|
* ```ts
|
|
@@ -116,9 +171,27 @@ export const cachedWithTTL = circular.cached;
|
|
|
116
171
|
*/
|
|
117
172
|
export const cachedInvalidateWithTTL = circular.cachedInvalidateWithTTL;
|
|
118
173
|
/**
|
|
119
|
-
* Returns an effect that computes a result
|
|
120
|
-
* evaluations
|
|
121
|
-
*
|
|
174
|
+
* Returns an effect that lazily computes a result and caches it for subsequent
|
|
175
|
+
* evaluations.
|
|
176
|
+
*
|
|
177
|
+
* **Details**
|
|
178
|
+
*
|
|
179
|
+
* This function wraps an effect and ensures that its result is computed only
|
|
180
|
+
* once. Once the result is computed, it is cached, meaning that subsequent
|
|
181
|
+
* evaluations of the same effect will return the cached result without
|
|
182
|
+
* re-executing the logic.
|
|
183
|
+
*
|
|
184
|
+
* **When to Use**
|
|
185
|
+
*
|
|
186
|
+
* Use this function when you have an expensive or time-consuming operation that
|
|
187
|
+
* you want to avoid repeating. The first evaluation will compute the result,
|
|
188
|
+
* and all following evaluations will immediately return the cached value,
|
|
189
|
+
* improving performance and reducing unnecessary work.
|
|
190
|
+
*
|
|
191
|
+
* @see {@link cachedWithTTL} for a similar function that includes a
|
|
192
|
+
* time-to-live duration for the cached value.
|
|
193
|
+
* @see {@link cachedInvalidateWithTTL} for a similar function that includes an
|
|
194
|
+
* additional effect for manually invalidating the cached value.
|
|
122
195
|
*
|
|
123
196
|
* @example
|
|
124
197
|
* ```ts
|
|
@@ -162,9 +235,30 @@ export const cachedInvalidateWithTTL = circular.cachedInvalidateWithTTL;
|
|
|
162
235
|
*/
|
|
163
236
|
export const cached = effect.memoize;
|
|
164
237
|
/**
|
|
165
|
-
* Returns a memoized version of a function with effects
|
|
166
|
-
*
|
|
167
|
-
*
|
|
238
|
+
* Returns a memoized version of a function with effects, reusing results for
|
|
239
|
+
* the same inputs.
|
|
240
|
+
*
|
|
241
|
+
* **Details**
|
|
242
|
+
*
|
|
243
|
+
* This function creates a memoized version of a given function that performs an
|
|
244
|
+
* effect. Memoization ensures that once a result is computed for a specific
|
|
245
|
+
* input, it is stored and reused for subsequent calls with the same input,
|
|
246
|
+
* reducing the need to recompute the result.
|
|
247
|
+
*
|
|
248
|
+
* The function can optionally take an `Equivalence` parameter to
|
|
249
|
+
* determine how inputs are compared for caching purposes.
|
|
250
|
+
*
|
|
251
|
+
* **When to Use**
|
|
252
|
+
*
|
|
253
|
+
* Use this function when you have a function that performs an effect and you
|
|
254
|
+
* want to avoid recomputing the result for the same input multiple times.
|
|
255
|
+
*
|
|
256
|
+
* It's ideal for functions that produce deterministic results based on their
|
|
257
|
+
* inputs, and you want to improve performance by caching the output.
|
|
258
|
+
*
|
|
259
|
+
* This is particularly useful in scenarios where the function involves
|
|
260
|
+
* expensive calculations or operations that should be avoided after the first
|
|
261
|
+
* execution with the same parameters.
|
|
168
262
|
*
|
|
169
263
|
* @example
|
|
170
264
|
* ```ts
|
|
@@ -200,6 +294,20 @@ export const cachedFunction = circular.cachedFunction;
|
|
|
200
294
|
* Returns an effect that executes only once, regardless of how many times it's
|
|
201
295
|
* called.
|
|
202
296
|
*
|
|
297
|
+
* **Details**
|
|
298
|
+
*
|
|
299
|
+
* This function ensures that a specific effect is executed only a single time,
|
|
300
|
+
* no matter how many times it is invoked. The result of the effect will be
|
|
301
|
+
* cached, and subsequent calls to the effect will immediately return the cached
|
|
302
|
+
* result without re-executing the original logic.
|
|
303
|
+
*
|
|
304
|
+
* **When to Use**
|
|
305
|
+
*
|
|
306
|
+
* Use this function when you need to perform a task only once, regardless of
|
|
307
|
+
* how many times the effect is triggered. It's particularly useful when you
|
|
308
|
+
* have initialization tasks, logging, or other one-time actions that should not
|
|
309
|
+
* be repeated. This can help optimize performance and avoid redundant actions.
|
|
310
|
+
*
|
|
203
311
|
* @example
|
|
204
312
|
* ```ts
|
|
205
313
|
* import { Effect, Console } from "effect"
|
|
@@ -227,9 +335,9 @@ export const once = effect.once;
|
|
|
227
335
|
* Combines multiple effects into one, returning results based on the input
|
|
228
336
|
* structure.
|
|
229
337
|
*
|
|
230
|
-
* **
|
|
338
|
+
* **Details**
|
|
231
339
|
*
|
|
232
|
-
* Use
|
|
340
|
+
* Use this function when you need to run multiple effects and combine their
|
|
233
341
|
* results into a single output. It supports tuples, iterables, structs, and
|
|
234
342
|
* records, making it flexible for different input types.
|
|
235
343
|
*
|
|
@@ -252,8 +360,8 @@ export const once = effect.once;
|
|
|
252
360
|
*
|
|
253
361
|
* **Short-Circuiting Behavior**
|
|
254
362
|
*
|
|
255
|
-
*
|
|
256
|
-
*
|
|
363
|
+
* This function stops execution on the first error it encounters, this is
|
|
364
|
+
* called "short-circuiting". If any effect in the collection fails, the
|
|
257
365
|
* remaining effects will not run, and the error will be propagated. To change
|
|
258
366
|
* this behavior, you can use the `mode` option, which allows all effects to run
|
|
259
367
|
* and collect results as `Either` or `Option`.
|
|
@@ -271,6 +379,7 @@ export const once = effect.once;
|
|
|
271
379
|
* the error for failure.
|
|
272
380
|
*
|
|
273
381
|
* @see {@link forEach} for iterating over elements and applying an effect.
|
|
382
|
+
* @see {@link allWith} for a data-last version of this function.
|
|
274
383
|
*
|
|
275
384
|
* @example
|
|
276
385
|
* ```ts
|
|
@@ -435,9 +544,9 @@ export const all = fiberRuntime.all;
|
|
|
435
544
|
*
|
|
436
545
|
* **When to Use**
|
|
437
546
|
*
|
|
438
|
-
*
|
|
439
|
-
* such as concurrency levels. This version is useful in functional
|
|
440
|
-
* your data and then apply operations to it.
|
|
547
|
+
* This function enables you to combine multiple effects and customize execution
|
|
548
|
+
* options such as concurrency levels. This version is useful in functional
|
|
549
|
+
* pipelines where you first define your data and then apply operations to it.
|
|
441
550
|
*
|
|
442
551
|
* @example
|
|
443
552
|
* ```ts
|
|
@@ -471,45 +580,353 @@ export const all = fiberRuntime.all;
|
|
|
471
580
|
*/
|
|
472
581
|
export const allWith = fiberRuntime.allWith;
|
|
473
582
|
/**
|
|
474
|
-
*
|
|
475
|
-
*
|
|
583
|
+
* Evaluates and runs each effect in the iterable, collecting only the
|
|
584
|
+
* successful results while discarding failures.
|
|
585
|
+
*
|
|
586
|
+
* **Details**
|
|
587
|
+
*
|
|
588
|
+
* This function function processes an iterable of effects and runs each one. If
|
|
589
|
+
* an effect is successful, its result is collected; if it fails, the result is
|
|
590
|
+
* discarded. This ensures that only successful outcomes are kept.
|
|
591
|
+
*
|
|
592
|
+
* **Options**
|
|
593
|
+
*
|
|
594
|
+
* The function also allows you to customize how the effects are handled by
|
|
595
|
+
* specifying options such as concurrency, batching, and how finalizers behave.
|
|
596
|
+
* These options provide flexibility in running the effects concurrently or
|
|
597
|
+
* adjusting other execution details.
|
|
598
|
+
*
|
|
599
|
+
* @example
|
|
600
|
+
* ```ts
|
|
601
|
+
* import { Effect } from "effect"
|
|
602
|
+
*
|
|
603
|
+
* const tasks = [
|
|
604
|
+
* Effect.succeed(1),
|
|
605
|
+
* Effect.fail("Error 1"),
|
|
606
|
+
* Effect.succeed(2),
|
|
607
|
+
* Effect.fail("Error 2")
|
|
608
|
+
* ]
|
|
609
|
+
*
|
|
610
|
+
* const program = Effect.gen(function*() {
|
|
611
|
+
* const successfulResults = yield* Effect.allSuccesses(tasks)
|
|
612
|
+
* console.log(successfulResults)
|
|
613
|
+
* })
|
|
614
|
+
*
|
|
615
|
+
* Effect.runFork(program)
|
|
616
|
+
* // Output: [1, 2]
|
|
617
|
+
*
|
|
618
|
+
* ```
|
|
476
619
|
*
|
|
477
620
|
* @since 2.0.0
|
|
478
621
|
* @category Collecting
|
|
479
622
|
*/
|
|
480
623
|
export const allSuccesses = fiberRuntime.allSuccesses;
|
|
481
624
|
/**
|
|
482
|
-
* Drops
|
|
625
|
+
* Drops elements until the effectful predicate returns `true`.
|
|
626
|
+
*
|
|
627
|
+
* **Details**
|
|
628
|
+
*
|
|
629
|
+
* This function processes a collection of elements and uses an effectful
|
|
630
|
+
* predicate to determine when to stop dropping elements. It drops elements from
|
|
631
|
+
* the beginning of the collection until the predicate returns `true`.
|
|
632
|
+
*
|
|
633
|
+
* The predicate is a function that takes an element and its index in the
|
|
634
|
+
* collection and returns an effect that evaluates to a boolean.
|
|
635
|
+
*
|
|
636
|
+
* Once the predicate returns `true`, the remaining elements of the collection
|
|
637
|
+
* are returned.
|
|
638
|
+
*
|
|
639
|
+
* **Note**: The first element for which the predicate returns `true` is also
|
|
640
|
+
* dropped.
|
|
641
|
+
*
|
|
642
|
+
* **When to Use**
|
|
643
|
+
*
|
|
644
|
+
* This function allows you to conditionally skip over a part of the collection
|
|
645
|
+
* based on some criteria defined in the predicate.
|
|
646
|
+
*
|
|
647
|
+
* @see {@link dropWhile} for a similar function that drops elements while the
|
|
648
|
+
* predicate returns `true`.
|
|
649
|
+
*
|
|
650
|
+
* @example
|
|
651
|
+
* ```ts
|
|
652
|
+
* import { Effect } from "effect"
|
|
653
|
+
*
|
|
654
|
+
* const numbers = [1, 2, 3, 4, 5, 6]
|
|
655
|
+
* const predicate = (n: number, i: number) => Effect.succeed(n > 3)
|
|
656
|
+
*
|
|
657
|
+
* const program = Effect.gen(function*() {
|
|
658
|
+
* const result = yield* Effect.dropUntil(numbers, predicate)
|
|
659
|
+
* console.log(result)
|
|
660
|
+
* })
|
|
661
|
+
*
|
|
662
|
+
* Effect.runFork(program)
|
|
663
|
+
* // Output: [5, 6]
|
|
664
|
+
* ```
|
|
483
665
|
*
|
|
484
666
|
* @since 2.0.0
|
|
485
667
|
* @category Collecting
|
|
486
668
|
*/
|
|
487
669
|
export const dropUntil = effect.dropUntil;
|
|
488
670
|
/**
|
|
489
|
-
* Drops
|
|
671
|
+
* Drops elements as long as the predicate returns `true`.
|
|
672
|
+
*
|
|
673
|
+
* **Details**
|
|
674
|
+
*
|
|
675
|
+
* This function processes a collection of elements and uses a predicate to
|
|
676
|
+
* decide whether to drop an element.
|
|
677
|
+
*
|
|
678
|
+
* The predicate is a function that takes an element and its index, and it
|
|
679
|
+
* returns an effect that evaluates to a boolean.
|
|
680
|
+
*
|
|
681
|
+
* As long as the predicate returns `true`, elements will continue to be dropped
|
|
682
|
+
* from the collection.
|
|
683
|
+
*
|
|
684
|
+
* Once the predicate returns `false`, the remaining elements are kept.
|
|
685
|
+
*
|
|
686
|
+
* **When to Use**
|
|
687
|
+
*
|
|
688
|
+
* This function allows you to discard elements from the start of a collection
|
|
689
|
+
* based on a condition, and only keep the rest when the condition no longer
|
|
690
|
+
* holds.
|
|
691
|
+
*
|
|
692
|
+
* @see {@link dropUntil} for a similar function that drops elements until the
|
|
693
|
+
* predicate returns `true`.
|
|
694
|
+
*
|
|
695
|
+
* @example
|
|
696
|
+
* ```ts
|
|
697
|
+
* import { Effect } from "effect"
|
|
698
|
+
*
|
|
699
|
+
* const numbers = [1, 2, 3, 4, 5, 6]
|
|
700
|
+
* const predicate = (n: number, i: number) => Effect.succeed(n <= 3)
|
|
701
|
+
*
|
|
702
|
+
* const program = Effect.gen(function*() {
|
|
703
|
+
* const result = yield* Effect.dropWhile(numbers, predicate)
|
|
704
|
+
* console.log(result)
|
|
705
|
+
* })
|
|
706
|
+
*
|
|
707
|
+
* Effect.runFork(program)
|
|
708
|
+
* // Output: [4, 5, 6]
|
|
709
|
+
* ```
|
|
490
710
|
*
|
|
491
711
|
* @since 2.0.0
|
|
492
712
|
* @category Collecting
|
|
493
713
|
*/
|
|
494
714
|
export const dropWhile = effect.dropWhile;
|
|
495
715
|
/**
|
|
496
|
-
*
|
|
497
|
-
*
|
|
716
|
+
* Takes elements from a collection until the effectful predicate returns
|
|
717
|
+
* `true`.
|
|
718
|
+
*
|
|
719
|
+
* **Details**
|
|
720
|
+
*
|
|
721
|
+
* This function processes a collection of elements and uses an effectful
|
|
722
|
+
* predicate to decide when to stop taking elements. The elements are taken from
|
|
723
|
+
* the beginning of the collection until the predicate returns `true`.
|
|
724
|
+
*
|
|
725
|
+
* The predicate is a function that takes an element and its index in the
|
|
726
|
+
* collection, and returns an effect that resolves to a boolean.
|
|
727
|
+
*
|
|
728
|
+
* Once the predicate returns `true`, the remaining elements of the collection
|
|
729
|
+
* are discarded, and the function stops taking more elements.
|
|
730
|
+
*
|
|
731
|
+
* **Note**: The first element for which the predicate returns `true` is also
|
|
732
|
+
* included in the result.
|
|
733
|
+
*
|
|
734
|
+
* **When to Use**
|
|
735
|
+
*
|
|
736
|
+
* Use this function when you want to conditionally take elements from a
|
|
737
|
+
* collection based on a dynamic condition. For example, you may want to collect
|
|
738
|
+
* numbers from a list until a certain threshold is reached, or gather items
|
|
739
|
+
* until a specific condition is met.
|
|
740
|
+
*
|
|
741
|
+
* @see {@link takeWhile} for a similar function that takes elements while the
|
|
742
|
+
* predicate returns `true`.
|
|
743
|
+
*
|
|
744
|
+
* @example
|
|
745
|
+
* ```ts
|
|
746
|
+
* import { Effect } from "effect"
|
|
747
|
+
*
|
|
748
|
+
* const numbers = [1, 2, 3, 4, 5, 6]
|
|
749
|
+
* const predicate = (n: number, i: number) => Effect.succeed(n > 3)
|
|
750
|
+
*
|
|
751
|
+
* const program = Effect.gen(function*() {
|
|
752
|
+
* const result = yield* Effect.takeUntil(numbers, predicate)
|
|
753
|
+
* console.log(result)
|
|
754
|
+
* })
|
|
755
|
+
*
|
|
756
|
+
* Effect.runFork(program)
|
|
757
|
+
* // Output: [ 1, 2, 3, 4 ]
|
|
758
|
+
* ```
|
|
759
|
+
*
|
|
760
|
+
* @since 2.0.0
|
|
761
|
+
* @category Collecting
|
|
762
|
+
*/
|
|
763
|
+
export const takeUntil = effect.takeUntil;
|
|
764
|
+
/**
|
|
765
|
+
* Takes elements as long as the predicate returns `true`.
|
|
766
|
+
*
|
|
767
|
+
* **Details**
|
|
768
|
+
*
|
|
769
|
+
* This function processes a collection of elements and uses a predicate to
|
|
770
|
+
* decide whether to take an element.
|
|
771
|
+
*
|
|
772
|
+
* The predicate is a function that takes an element and its index, and it
|
|
773
|
+
* returns an effect that evaluates to a boolean.
|
|
774
|
+
*
|
|
775
|
+
* As long as the predicate returns `true`, elements will continue to be taken
|
|
776
|
+
* from the collection.
|
|
777
|
+
*
|
|
778
|
+
* Once the predicate returns `false`, the remaining elements are discarded.
|
|
779
|
+
*
|
|
780
|
+
* @see {@link takeUntil} for a similar function that takes elements until the predicate returns `true`.
|
|
781
|
+
*
|
|
782
|
+
* @example
|
|
783
|
+
* ```ts
|
|
784
|
+
* import { Effect } from "effect"
|
|
785
|
+
*
|
|
786
|
+
* const numbers = [1, 2, 3, 4, 5, 6]
|
|
787
|
+
* const predicate = (n: number, i: number) => Effect.succeed(n <= 3)
|
|
788
|
+
*
|
|
789
|
+
* const program = Effect.gen(function*() {
|
|
790
|
+
* const result = yield* Effect.takeWhile(numbers, predicate)
|
|
791
|
+
* console.log(result)
|
|
792
|
+
* })
|
|
793
|
+
*
|
|
794
|
+
* Effect.runFork(program)
|
|
795
|
+
* // Output: [1, 2, 3]
|
|
796
|
+
* ```
|
|
797
|
+
*
|
|
798
|
+
* @since 2.0.0
|
|
799
|
+
* @category Collecting
|
|
800
|
+
*/
|
|
801
|
+
export const takeWhile = effect.takeWhile;
|
|
802
|
+
/**
|
|
803
|
+
* Determines whether all elements of the iterable satisfy the effectful
|
|
804
|
+
* predicate.
|
|
805
|
+
*
|
|
806
|
+
* **Details**
|
|
807
|
+
*
|
|
808
|
+
* This function checks whether every element in a given collection (an
|
|
809
|
+
* iterable) satisfies a condition defined by an effectful predicate.
|
|
810
|
+
*
|
|
811
|
+
* The predicate is a function that takes an element and its index, and it
|
|
812
|
+
* returns an effect that evaluates to a boolean.
|
|
813
|
+
*
|
|
814
|
+
* The function will process each element and return `true` if all elements
|
|
815
|
+
* satisfy the predicate; otherwise, it returns `false`.
|
|
816
|
+
*
|
|
817
|
+
* **When to Use**
|
|
818
|
+
*
|
|
819
|
+
* This function is useful when you need to verify that all items in a
|
|
820
|
+
* collection meet certain criteria, even when the evaluation of each item
|
|
821
|
+
* involves effects, such as asynchronous checks or complex computations.
|
|
822
|
+
*
|
|
823
|
+
* @see {@link exists} for a similar function that returns a boolean indicating
|
|
824
|
+
* whether **any** element satisfies the predicate.
|
|
825
|
+
*
|
|
826
|
+
* @example
|
|
827
|
+
* ```ts
|
|
828
|
+
* import { Effect } from "effect"
|
|
829
|
+
*
|
|
830
|
+
* const numbers = [2, 4, 6, 8]
|
|
831
|
+
* const predicate = (n: number, i: number) => Effect.succeed(n % 2 === 0)
|
|
832
|
+
*
|
|
833
|
+
* const program = Effect.gen(function*() {
|
|
834
|
+
* const allEven = yield* Effect.every(numbers, predicate)
|
|
835
|
+
* console.log(allEven)
|
|
836
|
+
* })
|
|
837
|
+
*
|
|
838
|
+
* Effect.runFork(program)
|
|
839
|
+
* // Output: true
|
|
840
|
+
* ```
|
|
498
841
|
*
|
|
499
842
|
* @since 2.0.0
|
|
500
843
|
* @category Condition Checking
|
|
501
844
|
*/
|
|
502
845
|
export const every = effect.every;
|
|
503
846
|
/**
|
|
504
|
-
* Determines whether any element of the
|
|
505
|
-
* predicate
|
|
847
|
+
* Determines whether any element of the iterable satisfies the effectual
|
|
848
|
+
* predicate.
|
|
849
|
+
*
|
|
850
|
+
* **Details**
|
|
851
|
+
*
|
|
852
|
+
* This function checks whether any element in a given collection (an iterable)
|
|
853
|
+
* satisfies a condition defined by an effectful predicate.
|
|
854
|
+
*
|
|
855
|
+
* The predicate is a function that takes an element and its index, and it
|
|
856
|
+
* returns an effect that evaluates to a boolean.
|
|
857
|
+
*
|
|
858
|
+
* The function will process each element, and if any element satisfies the
|
|
859
|
+
* predicate (returns `true`), the function will immediately return `true`.
|
|
860
|
+
*
|
|
861
|
+
* If none of the elements satisfy the condition, it will return `false`.
|
|
862
|
+
*
|
|
863
|
+
* **When to Use**
|
|
864
|
+
*
|
|
865
|
+
* This function allows you to quickly check for a condition in a collection
|
|
866
|
+
* without having to manually iterate over it.
|
|
867
|
+
*
|
|
868
|
+
* @see {@link every} for a similar function that checks if **all** elements
|
|
869
|
+
* satisfy the predicate.
|
|
870
|
+
*
|
|
871
|
+
* @example
|
|
872
|
+
* ```ts
|
|
873
|
+
* import { Effect } from "effect"
|
|
874
|
+
*
|
|
875
|
+
* const numbers = [1, 2, 3, 4]
|
|
876
|
+
* const predicate = (n: number, i: number) => Effect.succeed(n > 2)
|
|
877
|
+
*
|
|
878
|
+
* const program = Effect.gen(function*() {
|
|
879
|
+
* const hasLargeNumber = yield* Effect.exists(numbers, predicate)
|
|
880
|
+
* console.log(hasLargeNumber)
|
|
881
|
+
* })
|
|
882
|
+
*
|
|
883
|
+
* Effect.runFork(program)
|
|
884
|
+
* // Output: true
|
|
885
|
+
* ```
|
|
506
886
|
*
|
|
507
887
|
* @since 2.0.0
|
|
508
888
|
* @category Condition Checking
|
|
509
889
|
*/
|
|
510
890
|
export const exists = fiberRuntime.exists;
|
|
511
891
|
/**
|
|
512
|
-
* Filters
|
|
892
|
+
* Filters an iterable using the specified effectful predicate.
|
|
893
|
+
*
|
|
894
|
+
* **Details**
|
|
895
|
+
*
|
|
896
|
+
* This function filters a collection (an iterable) by applying an effectful
|
|
897
|
+
* predicate.
|
|
898
|
+
*
|
|
899
|
+
* The predicate is a function that takes an element and its index, and it
|
|
900
|
+
* returns an effect that evaluates to a boolean.
|
|
901
|
+
*
|
|
902
|
+
* The function processes each element in the collection and keeps only those
|
|
903
|
+
* that satisfy the condition defined by the predicate.
|
|
904
|
+
*
|
|
905
|
+
* **Options**
|
|
906
|
+
*
|
|
907
|
+
* You can also adjust the behavior with options such as concurrency, batching,
|
|
908
|
+
* or whether to negate the condition.
|
|
909
|
+
*
|
|
910
|
+
* **When to Use**
|
|
911
|
+
*
|
|
912
|
+
* This function allows you to selectively keep or remove elements based on a
|
|
913
|
+
* condition that may involve asynchronous or side-effect-causing operations.
|
|
914
|
+
*
|
|
915
|
+
* @example
|
|
916
|
+
* ```ts
|
|
917
|
+
* import { Effect } from "effect"
|
|
918
|
+
*
|
|
919
|
+
* const numbers = [1, 2, 3, 4, 5]
|
|
920
|
+
* const predicate = (n: number, i: number) => Effect.succeed(n % 2 === 0)
|
|
921
|
+
*
|
|
922
|
+
* const program = Effect.gen(function*() {
|
|
923
|
+
* const result = yield* Effect.filter(numbers, predicate)
|
|
924
|
+
* console.log(result)
|
|
925
|
+
* })
|
|
926
|
+
*
|
|
927
|
+
* Effect.runFork(program)
|
|
928
|
+
* // Output: [2, 4]
|
|
929
|
+
* ```
|
|
513
930
|
*
|
|
514
931
|
* @since 2.0.0
|
|
515
932
|
* @category Filtering
|
|
@@ -523,8 +940,6 @@ export const filter = fiberRuntime.filter;
|
|
|
523
940
|
* element is kept; if it returns `None`, the element is removed. The operation
|
|
524
941
|
* is done sequentially for each element.
|
|
525
942
|
*
|
|
526
|
-
* @see {@link filter} for concurrent filtering without mapping.
|
|
527
|
-
*
|
|
528
943
|
* @example
|
|
529
944
|
* ```ts
|
|
530
945
|
* import { Console, Effect, Option } from "effect"
|
|
@@ -556,6 +971,41 @@ export const filterMap = effect.filterMap;
|
|
|
556
971
|
/**
|
|
557
972
|
* Returns the first element that satisfies the effectful predicate.
|
|
558
973
|
*
|
|
974
|
+
* **Details**
|
|
975
|
+
*
|
|
976
|
+
* This function processes a collection of elements and applies an effectful
|
|
977
|
+
* predicate to each element.
|
|
978
|
+
*
|
|
979
|
+
* The predicate is a function that takes an element and its index in the
|
|
980
|
+
* collection, and it returns an effect that evaluates to a boolean.
|
|
981
|
+
*
|
|
982
|
+
* The function stops as soon as it finds the first element for which the
|
|
983
|
+
* predicate returns `true` and returns that element wrapped in an `Option`.
|
|
984
|
+
*
|
|
985
|
+
* If no element satisfies the predicate, the result will be `None`.
|
|
986
|
+
*
|
|
987
|
+
* **When to Use**
|
|
988
|
+
*
|
|
989
|
+
* This function allows you to efficiently find an element that meets a specific
|
|
990
|
+
* condition, even when the evaluation involves effects like asynchronous
|
|
991
|
+
* operations or side effects.
|
|
992
|
+
*
|
|
993
|
+
* @example
|
|
994
|
+
* ```ts
|
|
995
|
+
* import { Effect } from "effect"
|
|
996
|
+
*
|
|
997
|
+
* const numbers = [1, 2, 3, 4, 5]
|
|
998
|
+
* const predicate = (n: number, i: number) => Effect.succeed(n > 3)
|
|
999
|
+
*
|
|
1000
|
+
* const program = Effect.gen(function*() {
|
|
1001
|
+
* const result = yield* Effect.findFirst(numbers, predicate)
|
|
1002
|
+
* console.log(result)
|
|
1003
|
+
* })
|
|
1004
|
+
*
|
|
1005
|
+
* Effect.runFork(program)
|
|
1006
|
+
* // Output: { _id: 'Option', _tag: 'Some', value: 4 }
|
|
1007
|
+
* ```
|
|
1008
|
+
*
|
|
559
1009
|
* @since 2.0.0
|
|
560
1010
|
* @category Collecting
|
|
561
1011
|
*/
|
|
@@ -565,8 +1015,8 @@ export const findFirst = effect.findFirst;
|
|
|
565
1015
|
*
|
|
566
1016
|
* **Details**
|
|
567
1017
|
*
|
|
568
|
-
*
|
|
569
|
-
*
|
|
1018
|
+
* This function applies a provided operation to each element in the iterable,
|
|
1019
|
+
* producing a new effect that returns an array of results.
|
|
570
1020
|
*
|
|
571
1021
|
* If any effect fails, the iteration stops immediately (short-circuiting), and
|
|
572
1022
|
* the error is propagated.
|
|
@@ -628,32 +1078,99 @@ export const findFirst = effect.findFirst;
|
|
|
628
1078
|
*/
|
|
629
1079
|
export const forEach = fiberRuntime.forEach;
|
|
630
1080
|
/**
|
|
631
|
-
* Returns
|
|
632
|
-
*
|
|
1081
|
+
* Returns the first element of the iterable if the collection is non-empty, or
|
|
1082
|
+
* fails with the error `NoSuchElementException` if the collection is empty.
|
|
1083
|
+
*
|
|
1084
|
+
* **When to Use**
|
|
1085
|
+
*
|
|
1086
|
+
* This function is useful when you need to retrieve the first item from a
|
|
1087
|
+
* collection and want to handle the case where the collection might be empty
|
|
1088
|
+
* without causing an unhandled exception.
|
|
1089
|
+
*
|
|
1090
|
+
* @example
|
|
1091
|
+
* ```ts
|
|
1092
|
+
* import { Effect } from "effect"
|
|
1093
|
+
*
|
|
1094
|
+
* // Simulate an async operation
|
|
1095
|
+
* const fetchNumbers = Effect.succeed([1, 2, 3]).pipe(Effect.delay("100 millis"))
|
|
1096
|
+
*
|
|
1097
|
+
* const program = Effect.gen(function*() {
|
|
1098
|
+
* const firstElement = yield* Effect.head(fetchNumbers)
|
|
1099
|
+
* console.log(firstElement)
|
|
1100
|
+
* })
|
|
1101
|
+
*
|
|
1102
|
+
* Effect.runFork(program)
|
|
1103
|
+
* // Output: 1
|
|
1104
|
+
* ```
|
|
633
1105
|
*
|
|
634
1106
|
* @since 2.0.0
|
|
635
1107
|
* @category Collecting
|
|
636
1108
|
*/
|
|
637
1109
|
export const head = effect.head;
|
|
638
1110
|
/**
|
|
639
|
-
* Merges an `Iterable<Effect<A, E, R>>` to a single effect
|
|
640
|
-
*
|
|
1111
|
+
* Merges an `Iterable<Effect<A, E, R>>` to a single effect.
|
|
1112
|
+
*
|
|
1113
|
+
* **Details**
|
|
1114
|
+
*
|
|
1115
|
+
* This function takes an iterable of effects and combines them into a single
|
|
1116
|
+
* effect. It does this by iterating over each effect in the collection and
|
|
1117
|
+
* applying a function that accumulates results into a "zero" value, which
|
|
1118
|
+
* starts with an initial value and is updated with each effect's success.
|
|
1119
|
+
*
|
|
1120
|
+
* The provided function `f` is called for each element in the iterable,
|
|
1121
|
+
* allowing you to specify how to combine the results.
|
|
1122
|
+
*
|
|
1123
|
+
* **Options**
|
|
1124
|
+
*
|
|
1125
|
+
* The function also allows you to customize how the effects are handled by
|
|
1126
|
+
* specifying options such as concurrency, batching, and how finalizers behave.
|
|
1127
|
+
* These options provide flexibility in running the effects concurrently or
|
|
1128
|
+
* adjusting other execution details.
|
|
1129
|
+
*
|
|
1130
|
+
* @example
|
|
1131
|
+
* ```ts
|
|
1132
|
+
* import { Effect } from "effect"
|
|
1133
|
+
*
|
|
1134
|
+
* const numbers = [Effect.succeed(1), Effect.succeed(2), Effect.succeed(3)]
|
|
1135
|
+
* const add = (sum: number, value: number, i: number) => sum + value
|
|
1136
|
+
* const zero = 0
|
|
1137
|
+
*
|
|
1138
|
+
* const program = Effect.gen(function*() {
|
|
1139
|
+
* const total = yield* Effect.mergeAll(numbers, zero, add)
|
|
1140
|
+
* console.log(total)
|
|
1141
|
+
* })
|
|
1142
|
+
*
|
|
1143
|
+
* Effect.runFork(program)
|
|
1144
|
+
* // Output: 6
|
|
1145
|
+
* ```
|
|
641
1146
|
*
|
|
642
1147
|
* @since 2.0.0
|
|
643
1148
|
* @category Collecting
|
|
644
1149
|
*/
|
|
645
1150
|
export const mergeAll = fiberRuntime.mergeAll;
|
|
646
1151
|
/**
|
|
647
|
-
*
|
|
648
|
-
*
|
|
649
|
-
*
|
|
1152
|
+
* Processes an iterable and applies an effectful function to each element,
|
|
1153
|
+
* categorizing the results into successes and failures.
|
|
1154
|
+
*
|
|
1155
|
+
* **Details**
|
|
650
1156
|
*
|
|
651
|
-
* This function
|
|
652
|
-
*
|
|
653
|
-
*
|
|
654
|
-
*
|
|
655
|
-
* without
|
|
656
|
-
*
|
|
1157
|
+
* This function processes each element in the provided iterable by applying an
|
|
1158
|
+
* effectful function to it. The results are then categorized into two separate
|
|
1159
|
+
* lists: one for failures and another for successes. This separation allows you
|
|
1160
|
+
* to handle the two categories differently. Failures are collected in a list
|
|
1161
|
+
* without interrupting the processing of the remaining elements, so the
|
|
1162
|
+
* operation continues even if some elements fail. This is particularly useful
|
|
1163
|
+
* when you need to handle both successful and failed results separately,
|
|
1164
|
+
* without stopping the entire process on encountering a failure.
|
|
1165
|
+
*
|
|
1166
|
+
* **When to Use**
|
|
1167
|
+
*
|
|
1168
|
+
* Use this function when you want to process a collection of items and handle
|
|
1169
|
+
* errors or failures without interrupting the processing of other items. It's
|
|
1170
|
+
* useful when you need to distinguish between successful and failed results and
|
|
1171
|
+
* process them separately, for example, when logging errors while continuing to
|
|
1172
|
+
* work with valid data. The function ensures that failures are captured, while
|
|
1173
|
+
* successes are processed normally.
|
|
657
1174
|
*
|
|
658
1175
|
* @see {@link validateAll} for a function that either collects all failures or all successes.
|
|
659
1176
|
* @see {@link validateFirst} for a function that stops at the first success.
|
|
@@ -682,78 +1199,309 @@ export const mergeAll = fiberRuntime.mergeAll;
|
|
|
682
1199
|
*/
|
|
683
1200
|
export const partition = fiberRuntime.partition;
|
|
684
1201
|
/**
|
|
685
|
-
*
|
|
686
|
-
* from left to right.
|
|
1202
|
+
* Reduces an `Iterable<A>` using an effectual function `f`, working
|
|
1203
|
+
* sequentially from left to right.
|
|
1204
|
+
*
|
|
1205
|
+
* **Details**
|
|
1206
|
+
*
|
|
1207
|
+
* This function takes an iterable and applies a function `f` to each element in
|
|
1208
|
+
* the iterable. The function works sequentially, starting with an initial value
|
|
1209
|
+
* `zero` and then combining it with each element in the collection. The
|
|
1210
|
+
* provided function `f` is called for each element in the iterable, allowing
|
|
1211
|
+
* you to accumulate a result based on the current value and the element being
|
|
1212
|
+
* processed.
|
|
1213
|
+
*
|
|
1214
|
+
* **When to Use**
|
|
1215
|
+
*
|
|
1216
|
+
* The function is often used for operations like summing a collection of
|
|
1217
|
+
* numbers or combining results from multiple tasks. It ensures that operations
|
|
1218
|
+
* are performed one after the other, maintaining the order of the elements.
|
|
1219
|
+
*
|
|
1220
|
+
* @see {@link reduceWhile} for a similar function that stops the process based on a predicate.
|
|
1221
|
+
* @see {@link reduceRight} for a similar function that works from right to left.
|
|
1222
|
+
*
|
|
1223
|
+
* @example
|
|
1224
|
+
* ```ts
|
|
1225
|
+
* import { Console, Effect } from "effect"
|
|
1226
|
+
*
|
|
1227
|
+
* const processOrder = (id: number) =>
|
|
1228
|
+
* Effect.succeed({ id, price: 100 * id })
|
|
1229
|
+
* .pipe(Effect.tap(() => Console.log(`Order ${id} processed`)), Effect.delay(500 - (id * 100)))
|
|
1230
|
+
*
|
|
1231
|
+
* const program = Effect.reduce(
|
|
1232
|
+
* [1, 2, 3, 4],
|
|
1233
|
+
* 0,
|
|
1234
|
+
* (acc, id, i) =>
|
|
1235
|
+
* processOrder(id)
|
|
1236
|
+
* .pipe(Effect.map((order) => acc + order.price))
|
|
1237
|
+
* )
|
|
1238
|
+
*
|
|
1239
|
+
* Effect.runPromise(program).then(console.log)
|
|
1240
|
+
* // Output:
|
|
1241
|
+
* // Order 1 processed
|
|
1242
|
+
* // Order 2 processed
|
|
1243
|
+
* // Order 3 processed
|
|
1244
|
+
* // Order 4 processed
|
|
1245
|
+
* // 1000
|
|
1246
|
+
* ```
|
|
687
1247
|
*
|
|
688
1248
|
* @since 2.0.0
|
|
689
1249
|
* @category Collecting
|
|
690
1250
|
*/
|
|
691
1251
|
export const reduce = effect.reduce;
|
|
692
1252
|
/**
|
|
693
|
-
* Reduces an `Iterable<
|
|
1253
|
+
* Reduces an `Iterable<A>` using an effectual function `body`, working
|
|
1254
|
+
* sequentially from left to right, stopping the process early when the
|
|
1255
|
+
* predicate `while` is not satisfied.
|
|
1256
|
+
*
|
|
1257
|
+
* **Details**
|
|
1258
|
+
*
|
|
1259
|
+
* This function processes a collection of elements, applying a function `body`
|
|
1260
|
+
* to reduce them to a single value, starting from the first element. It checks
|
|
1261
|
+
* the value of the accumulator against a predicate (`while`). If at any point
|
|
1262
|
+
* the predicate returns `false`, the reduction stops, and the accumulated
|
|
1263
|
+
* result is returned.
|
|
1264
|
+
*
|
|
1265
|
+
* **When to Use**
|
|
1266
|
+
*
|
|
1267
|
+
* Use this function when you need to reduce a collection of elements, but only
|
|
1268
|
+
* continue the process as long as a certain condition holds true. For example,
|
|
1269
|
+
* if you want to sum values in a list but stop as soon as the sum exceeds a
|
|
1270
|
+
* certain threshold, you can use this function.
|
|
1271
|
+
*
|
|
1272
|
+
* @example
|
|
1273
|
+
* ```ts
|
|
1274
|
+
* import { Console, Effect } from "effect"
|
|
1275
|
+
*
|
|
1276
|
+
* const processOrder = (id: number) =>
|
|
1277
|
+
* Effect.succeed({ id, price: 100 * id })
|
|
1278
|
+
* .pipe(Effect.tap(() => Console.log(`Order ${id} processed`)), Effect.delay(500 - (id * 100)))
|
|
1279
|
+
*
|
|
1280
|
+
* const program = Effect.reduceWhile(
|
|
1281
|
+
* [1, 2, 3, 4],
|
|
1282
|
+
* 0,
|
|
1283
|
+
* {
|
|
1284
|
+
* body: (acc, id, i) =>
|
|
1285
|
+
* processOrder(id)
|
|
1286
|
+
* .pipe(Effect.map((order) => acc + order.price)),
|
|
1287
|
+
* while: (acc) => acc < 500
|
|
1288
|
+
* }
|
|
1289
|
+
* )
|
|
1290
|
+
*
|
|
1291
|
+
* Effect.runPromise(program).then(console.log)
|
|
1292
|
+
* // Output:
|
|
1293
|
+
* // Order 1 processed
|
|
1294
|
+
* // Order 2 processed
|
|
1295
|
+
* // Order 3 processed
|
|
1296
|
+
* // 600
|
|
1297
|
+
* ```
|
|
694
1298
|
*
|
|
695
1299
|
* @since 2.0.0
|
|
696
1300
|
* @category Collecting
|
|
697
1301
|
*/
|
|
698
|
-
export const
|
|
1302
|
+
export const reduceWhile = effect.reduceWhile;
|
|
699
1303
|
/**
|
|
700
|
-
*
|
|
1304
|
+
* Reduces an `Iterable<A>` using an effectual function `f`, working
|
|
1305
|
+
* sequentially from right to left.
|
|
1306
|
+
*
|
|
1307
|
+
* **Details**
|
|
1308
|
+
*
|
|
1309
|
+
* This function takes an iterable and applies a function `f` to each element in
|
|
1310
|
+
* the iterable. The function works sequentially, starting with an initial value
|
|
1311
|
+
* `zero` and then combining it with each element in the collection. The
|
|
1312
|
+
* provided function `f` is called for each element in the iterable, allowing
|
|
1313
|
+
* you to accumulate a result based on the current value and the element being
|
|
1314
|
+
* processed.
|
|
1315
|
+
*
|
|
1316
|
+
* **When to Use**
|
|
1317
|
+
*
|
|
1318
|
+
* The function is often used for operations like summing a collection of
|
|
1319
|
+
* numbers or combining results from multiple tasks. It ensures that operations
|
|
1320
|
+
* are performed one after the other, maintaining the order of the elements.
|
|
1321
|
+
*
|
|
1322
|
+
* @see {@link reduce} for a similar function that works from left to right.
|
|
1323
|
+
*
|
|
1324
|
+
* @example
|
|
1325
|
+
* ```ts
|
|
1326
|
+
* import { Console, Effect } from "effect"
|
|
1327
|
+
*
|
|
1328
|
+
* const processOrder = (id: number) =>
|
|
1329
|
+
* Effect.succeed({ id, price: 100 * id })
|
|
1330
|
+
* .pipe(Effect.tap(() => Console.log(`Order ${id} processed`)), Effect.delay(500 - (id * 100)))
|
|
1331
|
+
*
|
|
1332
|
+
* const program = Effect.reduceRight(
|
|
1333
|
+
* [1, 2, 3, 4],
|
|
1334
|
+
* 0,
|
|
1335
|
+
* (id, acc, i) =>
|
|
1336
|
+
* processOrder(id)
|
|
1337
|
+
* .pipe(Effect.map((order) => acc + order.price))
|
|
1338
|
+
* )
|
|
1339
|
+
*
|
|
1340
|
+
* Effect.runPromise(program).then(console.log)
|
|
1341
|
+
* // Output:
|
|
1342
|
+
* // Order 4 processed
|
|
1343
|
+
* // Order 3 processed
|
|
1344
|
+
* // Order 2 processed
|
|
1345
|
+
* // Order 1 processed
|
|
1346
|
+
* // 1000
|
|
1347
|
+
* ```
|
|
701
1348
|
*
|
|
702
1349
|
* @since 2.0.0
|
|
703
1350
|
* @category Collecting
|
|
704
1351
|
*/
|
|
705
1352
|
export const reduceRight = effect.reduceRight;
|
|
706
1353
|
/**
|
|
707
|
-
*
|
|
708
|
-
*
|
|
1354
|
+
* Reduces an `Iterable<Effect<A, E, R>>` to a single effect.
|
|
1355
|
+
*
|
|
1356
|
+
* **Details**
|
|
1357
|
+
*
|
|
1358
|
+
* This function processes a collection of effects and combines them into one
|
|
1359
|
+
* single effect. It starts with an initial effect (`zero`) and applies a
|
|
1360
|
+
* function `f` to each element in the collection.
|
|
1361
|
+
*
|
|
1362
|
+
* **Options**
|
|
1363
|
+
*
|
|
1364
|
+
* The function also allows you to customize how the effects are handled by
|
|
1365
|
+
* specifying options such as concurrency, batching, and how finalizers behave.
|
|
1366
|
+
* These options provide flexibility in running the effects concurrently or
|
|
1367
|
+
* adjusting other execution details.
|
|
1368
|
+
*
|
|
1369
|
+
* @example
|
|
1370
|
+
* ```ts
|
|
1371
|
+
* import { Console, Effect } from "effect"
|
|
1372
|
+
*
|
|
1373
|
+
* const processOrder = (id: number) =>
|
|
1374
|
+
* Effect.succeed({ id, price: 100 * id })
|
|
1375
|
+
* .pipe(Effect.tap(() => Console.log(`Order ${id} processed`)), Effect.delay(500 - (id * 100)))
|
|
1376
|
+
*
|
|
1377
|
+
* const program = Effect.reduceEffect(
|
|
1378
|
+
* [processOrder(1), processOrder(2), processOrder(3), processOrder(4)],
|
|
1379
|
+
* Effect.succeed(0),
|
|
1380
|
+
* (acc, order, i) => acc + order.price
|
|
1381
|
+
* )
|
|
1382
|
+
*
|
|
1383
|
+
* Effect.runPromise(program).then(console.log)
|
|
1384
|
+
* // Output:
|
|
1385
|
+
* // Order 1 processed
|
|
1386
|
+
* // Order 2 processed
|
|
1387
|
+
* // Order 3 processed
|
|
1388
|
+
* // Order 4 processed
|
|
1389
|
+
* // 1000
|
|
1390
|
+
* ```
|
|
709
1391
|
*
|
|
710
1392
|
* @since 2.0.0
|
|
711
1393
|
* @category Collecting
|
|
712
1394
|
*/
|
|
713
|
-
export const
|
|
1395
|
+
export const reduceEffect = fiberRuntime.reduceEffect;
|
|
714
1396
|
/**
|
|
715
1397
|
* Replicates the given effect `n` times.
|
|
716
1398
|
*
|
|
1399
|
+
* **Details**
|
|
1400
|
+
*
|
|
1401
|
+
* This function takes an effect and replicates it a specified number of times
|
|
1402
|
+
* (`n`). The result is an array of `n` effects, each of which is identical to
|
|
1403
|
+
* the original effect.
|
|
1404
|
+
*
|
|
1405
|
+
* @example
|
|
1406
|
+
* ```ts
|
|
1407
|
+
* import { Console, Effect } from "effect"
|
|
1408
|
+
*
|
|
1409
|
+
* const task = Effect.succeed("Hello, World!").pipe(
|
|
1410
|
+
* Effect.tap(Console.log)
|
|
1411
|
+
* )
|
|
1412
|
+
*
|
|
1413
|
+
* const program = Effect.gen(function*() {
|
|
1414
|
+
* // Replicate the task 3 times
|
|
1415
|
+
* const tasks = Effect.replicate(task, 3)
|
|
1416
|
+
* for (const t of tasks) {
|
|
1417
|
+
* // Run each task
|
|
1418
|
+
* yield* t
|
|
1419
|
+
* }
|
|
1420
|
+
* })
|
|
1421
|
+
*
|
|
1422
|
+
* Effect.runFork(program)
|
|
1423
|
+
* // Output:
|
|
1424
|
+
* // Hello, World!
|
|
1425
|
+
* // Hello, World!
|
|
1426
|
+
* // Hello, World!
|
|
1427
|
+
* ```
|
|
1428
|
+
*
|
|
717
1429
|
* @since 2.0.0
|
|
718
1430
|
*/
|
|
719
1431
|
export const replicate = fiberRuntime.replicate;
|
|
720
1432
|
/**
|
|
721
|
-
* Performs this effect the specified number of times and collects the
|
|
722
|
-
*
|
|
1433
|
+
* Performs this effect the specified number of times and collects the results.
|
|
1434
|
+
*
|
|
1435
|
+
* **Details**
|
|
1436
|
+
*
|
|
1437
|
+
* This function repeats an effect multiple times and collects the results into
|
|
1438
|
+
* an array. You specify how many times to execute the effect, and it runs that
|
|
1439
|
+
* many times, either in sequence or concurrently depending on the provided
|
|
1440
|
+
* options.
|
|
1441
|
+
*
|
|
1442
|
+
* **Options**
|
|
1443
|
+
*
|
|
1444
|
+
* If the `discard` option is set to `true`, the intermediate results are not
|
|
1445
|
+
* collected, and the final result of the operation is `void`.
|
|
1446
|
+
*
|
|
1447
|
+
* The function also allows you to customize how the effects are handled by
|
|
1448
|
+
* specifying options such as concurrency, batching, and how finalizers behave.
|
|
1449
|
+
* These options provide flexibility in running the effects concurrently or
|
|
1450
|
+
* adjusting other execution details.
|
|
1451
|
+
*
|
|
1452
|
+
* @example
|
|
1453
|
+
* ```ts
|
|
1454
|
+
* import { Console, Effect } from "effect"
|
|
1455
|
+
*
|
|
1456
|
+
* let counter = 0
|
|
1457
|
+
*
|
|
1458
|
+
* const task = Effect.sync(() => ++counter).pipe(
|
|
1459
|
+
* Effect.tap(() => Console.log(`Task completed`))
|
|
1460
|
+
* )
|
|
1461
|
+
*
|
|
1462
|
+
* const program = Effect.gen(function*() {
|
|
1463
|
+
* // Replicate the task 3 times and collect the results
|
|
1464
|
+
* const results = yield* Effect.replicateEffect(task, 3)
|
|
1465
|
+
* yield* Console.log(`Results: ${results.join(", ")}`)
|
|
1466
|
+
* })
|
|
1467
|
+
*
|
|
1468
|
+
* Effect.runFork(program)
|
|
1469
|
+
* // Output:
|
|
1470
|
+
* // Task completed
|
|
1471
|
+
* // Task completed
|
|
1472
|
+
* // Task completed
|
|
1473
|
+
* // Results: 1, 2, 3
|
|
1474
|
+
* ```
|
|
723
1475
|
*
|
|
724
1476
|
* @since 2.0.0
|
|
725
1477
|
* @category Collecting
|
|
726
1478
|
*/
|
|
727
1479
|
export const replicateEffect = fiberRuntime.replicateEffect;
|
|
728
1480
|
/**
|
|
729
|
-
*
|
|
1481
|
+
* Applies an effectful operation to each element in a collection while
|
|
1482
|
+
* collecting both successes and failures.
|
|
730
1483
|
*
|
|
731
|
-
*
|
|
732
|
-
* @category Collecting
|
|
733
|
-
*/
|
|
734
|
-
export const takeUntil = effect.takeUntil;
|
|
735
|
-
/**
|
|
736
|
-
* Takes all elements so long as the effectual predicate returns true.
|
|
1484
|
+
* **Details**
|
|
737
1485
|
*
|
|
738
|
-
*
|
|
739
|
-
*
|
|
740
|
-
*/
|
|
741
|
-
export const takeWhile = effect.takeWhile;
|
|
742
|
-
/**
|
|
743
|
-
* The `validateAll` function allows you to apply an effectful operation
|
|
744
|
-
* to each element of a collection, while collecting both the successes and
|
|
745
|
-
* failures. Unlike {@link forEach}, which would stop at the first error,
|
|
746
|
-
* `validateAll` continues processing all elements, accumulating both
|
|
747
|
-
* successes and failures.
|
|
1486
|
+
* This function allows you to apply an effectful operation to every item in a
|
|
1487
|
+
* collection.
|
|
748
1488
|
*
|
|
749
|
-
*
|
|
750
|
-
*
|
|
751
|
-
*
|
|
752
|
-
*
|
|
753
|
-
*
|
|
1489
|
+
* Unlike {@link forEach}, which would stop at the first error, this function
|
|
1490
|
+
* continues processing all elements, accumulating both successes and failures.
|
|
1491
|
+
*
|
|
1492
|
+
* **When to Use**
|
|
1493
|
+
*
|
|
1494
|
+
* Use this function when you want to process every item in a collection, even
|
|
1495
|
+
* if some items fail. This is particularly useful when you need to perform
|
|
1496
|
+
* operations on all elements without halting due to an error.
|
|
1497
|
+
*
|
|
1498
|
+
* Keep in mind that if there are any failures, **all successes will be lost**,
|
|
1499
|
+
* so this function is not suitable when you need to keep the successful results
|
|
1500
|
+
* in case of errors.
|
|
754
1501
|
*
|
|
755
1502
|
* @see {@link forEach} for a similar function that stops at the first error.
|
|
756
|
-
* @see {@link partition} when you need to separate successes and failures
|
|
1503
|
+
* @see {@link partition} when you need to separate successes and failures
|
|
1504
|
+
* instead of losing successes with errors.
|
|
757
1505
|
*
|
|
758
1506
|
* @example
|
|
759
1507
|
* ```ts
|
|
@@ -790,19 +1538,22 @@ export const takeWhile = effect.takeWhile;
|
|
|
790
1538
|
*/
|
|
791
1539
|
export const validateAll = fiberRuntime.validateAll;
|
|
792
1540
|
/**
|
|
793
|
-
*
|
|
794
|
-
*
|
|
795
|
-
*
|
|
1541
|
+
* This function is similar to {@link validateAll} but with a key difference: it
|
|
1542
|
+
* returns the first successful result or all errors if none of the operations
|
|
1543
|
+
* succeed.
|
|
1544
|
+
*
|
|
1545
|
+
* **Details**
|
|
796
1546
|
*
|
|
797
1547
|
* This function processes a collection of elements and applies an effectful
|
|
798
|
-
* operation to each. Unlike
|
|
799
|
-
* successes and failures, `validateFirst` stops and returns the first
|
|
1548
|
+
* operation to each. Unlike {@link validateAll}, which accumulates both
|
|
1549
|
+
* successes and failures, `Effect.validateFirst` stops and returns the first
|
|
800
1550
|
* success it encounters. If no success occurs, it returns all accumulated
|
|
801
1551
|
* errors. This can be useful when you are interested in the first successful
|
|
802
1552
|
* result and want to avoid processing further once a valid result is found.
|
|
803
1553
|
*
|
|
804
1554
|
* @see {@link validateAll} for a similar function that accumulates all results.
|
|
805
|
-
* @see {@link firstSuccessOf} for a similar function that processes multiple
|
|
1555
|
+
* @see {@link firstSuccessOf} for a similar function that processes multiple
|
|
1556
|
+
* effects and returns the first successful one or the last error.
|
|
806
1557
|
*
|
|
807
1558
|
* @example
|
|
808
1559
|
* ```ts
|
|
@@ -831,11 +1582,6 @@ export const validateFirst = fiberRuntime.validateFirst;
|
|
|
831
1582
|
/**
|
|
832
1583
|
* Creates an `Effect` from a callback-based asynchronous function.
|
|
833
1584
|
*
|
|
834
|
-
* **When to Use**
|
|
835
|
-
*
|
|
836
|
-
* Use `async` when dealing with APIs that use callback-style instead of
|
|
837
|
-
* `async/await` or `Promise`.
|
|
838
|
-
*
|
|
839
1585
|
* **Details**
|
|
840
1586
|
*
|
|
841
1587
|
* The `resume` function:
|
|
@@ -852,6 +1598,11 @@ export const validateFirst = fiberRuntime.validateFirst;
|
|
|
852
1598
|
* in cases where it is known will improve diagnostics, but not affect the
|
|
853
1599
|
* behavior of the returned effect.
|
|
854
1600
|
*
|
|
1601
|
+
* **When to Use**
|
|
1602
|
+
*
|
|
1603
|
+
* Use `Effect.async` when dealing with APIs that use callback-style instead of
|
|
1604
|
+
* `async/await` or `Promise`.
|
|
1605
|
+
*
|
|
855
1606
|
* @example
|
|
856
1607
|
* ```ts
|
|
857
1608
|
* // Title: Wrapping a Callback API
|
|
@@ -1011,16 +1762,22 @@ export const withFiberRuntime = core.withFiberRuntime;
|
|
|
1011
1762
|
*/
|
|
1012
1763
|
export const fail = core.fail;
|
|
1013
1764
|
/**
|
|
1765
|
+
* Creates an `Effect` that fails with the specified error, evaluated lazily.
|
|
1766
|
+
*
|
|
1014
1767
|
* @since 2.0.0
|
|
1015
1768
|
* @category Creating Effects
|
|
1016
1769
|
*/
|
|
1017
1770
|
export const failSync = core.failSync;
|
|
1018
1771
|
/**
|
|
1772
|
+
* Creates an `Effect` that fails with the specified `Cause`.
|
|
1773
|
+
*
|
|
1019
1774
|
* @since 2.0.0
|
|
1020
1775
|
* @category Creating Effects
|
|
1021
1776
|
*/
|
|
1022
1777
|
export const failCause = core.failCause;
|
|
1023
1778
|
/**
|
|
1779
|
+
* Creates an `Effect` that fails with the specified `Cause`, evaluated lazily.
|
|
1780
|
+
*
|
|
1024
1781
|
* @since 2.0.0
|
|
1025
1782
|
* @category Creating Effects
|
|
1026
1783
|
*/
|
|
@@ -1028,22 +1785,25 @@ export const failCauseSync = core.failCauseSync;
|
|
|
1028
1785
|
/**
|
|
1029
1786
|
* Creates an effect that terminates a fiber with a specified error.
|
|
1030
1787
|
*
|
|
1031
|
-
* **When to Use**
|
|
1032
|
-
*
|
|
1033
|
-
* Use `die` when encountering unexpected conditions in your code that should
|
|
1034
|
-
* not be handled as regular errors but instead represent unrecoverable defects.
|
|
1035
|
-
*
|
|
1036
1788
|
* **Details**
|
|
1037
1789
|
*
|
|
1038
|
-
*
|
|
1039
|
-
*
|
|
1040
|
-
*
|
|
1790
|
+
* This function is used to signal a defect, which represents a critical and
|
|
1791
|
+
* unexpected error in the code. When invoked, it produces an effect that does
|
|
1792
|
+
* not handle the error and instead terminates the fiber.
|
|
1041
1793
|
*
|
|
1042
1794
|
* The error channel of the resulting effect is of type `never`, indicating that
|
|
1043
1795
|
* it cannot recover from this failure.
|
|
1044
1796
|
*
|
|
1045
|
-
*
|
|
1046
|
-
*
|
|
1797
|
+
* **When to Use**
|
|
1798
|
+
*
|
|
1799
|
+
* Use this function when encountering unexpected conditions in your code that
|
|
1800
|
+
* should not be handled as regular errors but instead represent unrecoverable
|
|
1801
|
+
* defects.
|
|
1802
|
+
*
|
|
1803
|
+
* @see {@link dieSync} for a variant that throws a specified error, evaluated
|
|
1804
|
+
* lazily.
|
|
1805
|
+
* @see {@link dieMessage} for a variant that throws a `RuntimeException` with a
|
|
1806
|
+
* message.
|
|
1047
1807
|
*
|
|
1048
1808
|
* @example
|
|
1049
1809
|
* ```ts
|
|
@@ -1073,20 +1833,20 @@ export const die = core.die;
|
|
|
1073
1833
|
* Creates an effect that terminates a fiber with a `RuntimeException`
|
|
1074
1834
|
* containing the specified message.
|
|
1075
1835
|
*
|
|
1076
|
-
* **When to Use**
|
|
1077
|
-
*
|
|
1078
|
-
* Use `dieMessage` when you want to terminate a fiber due to an unrecoverable
|
|
1079
|
-
* defect and include a clear explanation in the message.
|
|
1080
|
-
*
|
|
1081
1836
|
* **Details**
|
|
1082
1837
|
*
|
|
1083
|
-
*
|
|
1084
|
-
*
|
|
1838
|
+
* This function is used to signal a defect, representing a critical and
|
|
1839
|
+
* unexpected error in the code. When invoked, it produces an effect that
|
|
1085
1840
|
* terminates the fiber with a `RuntimeException` carrying the given message.
|
|
1086
1841
|
*
|
|
1087
1842
|
* The resulting effect has an error channel of type `never`, indicating it does
|
|
1088
1843
|
* not handle or recover from the error.
|
|
1089
1844
|
*
|
|
1845
|
+
* **When to Use**
|
|
1846
|
+
*
|
|
1847
|
+
* Use this function when you want to terminate a fiber due to an unrecoverable
|
|
1848
|
+
* defect and include a clear explanation in the message.
|
|
1849
|
+
*
|
|
1090
1850
|
* @see {@link die} for a variant that throws a specified error.
|
|
1091
1851
|
* @see {@link dieSync} for a variant that throws a specified error, evaluated
|
|
1092
1852
|
* lazily.
|
|
@@ -1118,6 +1878,8 @@ export const dieMessage = core.dieMessage;
|
|
|
1118
1878
|
/**
|
|
1119
1879
|
* Creates an effect that dies with the specified error, evaluated lazily.
|
|
1120
1880
|
*
|
|
1881
|
+
* **Details**
|
|
1882
|
+
*
|
|
1121
1883
|
* This function allows you to create an effect that will terminate with a fatal error.
|
|
1122
1884
|
* The error is provided as a lazy argument, meaning it will only be evaluated when the effect runs.
|
|
1123
1885
|
*
|
|
@@ -1133,7 +1895,7 @@ export const dieSync = core.dieSync;
|
|
|
1133
1895
|
*
|
|
1134
1896
|
* **When to Use**
|
|
1135
1897
|
*
|
|
1136
|
-
* `gen` allows you to write code that looks and behaves like synchronous
|
|
1898
|
+
* `Effect.gen` allows you to write code that looks and behaves like synchronous
|
|
1137
1899
|
* code, but it can handle asynchronous tasks, errors, and complex control flow
|
|
1138
1900
|
* (like loops and conditions). It helps make asynchronous code more readable
|
|
1139
1901
|
* and easier to manage.
|
|
@@ -1177,28 +1939,44 @@ export const dieSync = core.dieSync;
|
|
|
1177
1939
|
*/
|
|
1178
1940
|
export const gen = core.gen;
|
|
1179
1941
|
/**
|
|
1180
|
-
*
|
|
1181
|
-
* `while(true) {}`, only without the wasted CPU cycles.
|
|
1942
|
+
* An effect that that runs indefinitely and never produces any result. The
|
|
1943
|
+
* moral equivalent of `while(true) {}`, only without the wasted CPU cycles.
|
|
1944
|
+
*
|
|
1945
|
+
* **When to Use**
|
|
1946
|
+
*
|
|
1947
|
+
* It could be useful for long-running background tasks or to simulate waiting
|
|
1948
|
+
* behavior without actually consuming resources. This effect is ideal for cases
|
|
1949
|
+
* where you want to keep the program alive or in a certain state without
|
|
1950
|
+
* performing any active work.
|
|
1182
1951
|
*
|
|
1183
1952
|
* @since 2.0.0
|
|
1184
1953
|
* @category Creating Effects
|
|
1185
1954
|
*/
|
|
1186
1955
|
export const never = core.never;
|
|
1187
1956
|
/**
|
|
1188
|
-
*
|
|
1957
|
+
* Ensures the `Option` is `None`, returning `void`. Otherwise, raises a
|
|
1958
|
+
* `NoSuchElementException`.
|
|
1959
|
+
*
|
|
1960
|
+
* **Details**
|
|
1961
|
+
*
|
|
1962
|
+
* This function checks if the provided `Option` is `None`. If it is, it returns
|
|
1963
|
+
* an effect that produces no result (i.e., `void`). If the `Option` is not
|
|
1964
|
+
* `None` (i.e., it contains a value), the function will raise a
|
|
1965
|
+
* `NoSuchElementException` error.
|
|
1966
|
+
*
|
|
1967
|
+
* **When to Use**
|
|
1968
|
+
*
|
|
1969
|
+
* This is useful when you want to ensure that a certain value is absent (i.e.,
|
|
1970
|
+
* `None`) before continuing execution, and to handle cases where the value is
|
|
1971
|
+
* unexpectedly present.
|
|
1189
1972
|
*
|
|
1190
1973
|
* @since 2.0.0
|
|
1191
|
-
* @category Creating Effects
|
|
1192
1974
|
*/
|
|
1193
1975
|
export const none = effect.none;
|
|
1194
1976
|
/**
|
|
1195
1977
|
* Creates an `Effect` that represents an asynchronous computation guaranteed to
|
|
1196
1978
|
* succeed.
|
|
1197
1979
|
*
|
|
1198
|
-
* **When to Use**
|
|
1199
|
-
*
|
|
1200
|
-
* Use `promise` when you are sure the operation will not reject.
|
|
1201
|
-
*
|
|
1202
1980
|
* **Details**
|
|
1203
1981
|
*
|
|
1204
1982
|
* The provided function (`thunk`) returns a `Promise` that should never reject; if it does, the error
|
|
@@ -1214,6 +1992,10 @@ export const none = effect.none;
|
|
|
1214
1992
|
* An optional `AbortSignal` can be provided to allow for interruption of the
|
|
1215
1993
|
* wrapped `Promise` API.
|
|
1216
1994
|
*
|
|
1995
|
+
* **When to Use**
|
|
1996
|
+
*
|
|
1997
|
+
* Use this function when you are sure the operation will not reject.
|
|
1998
|
+
*
|
|
1217
1999
|
* @see {@link tryPromise} for a version that can handle failures.
|
|
1218
2000
|
*
|
|
1219
2001
|
* @example
|
|
@@ -1269,6 +2051,15 @@ export const succeed = core.succeed;
|
|
|
1269
2051
|
/**
|
|
1270
2052
|
* Returns an effect which succeeds with `None`.
|
|
1271
2053
|
*
|
|
2054
|
+
* **When to Use**
|
|
2055
|
+
*
|
|
2056
|
+
* Use this function when you need to represent the absence of a value in your
|
|
2057
|
+
* code, especially when working with optional data. This can be helpful when
|
|
2058
|
+
* you want to indicate that no result is available without throwing an error or
|
|
2059
|
+
* performing additional logic.
|
|
2060
|
+
*
|
|
2061
|
+
* @see {@link succeedSome} to create an effect that succeeds with a `Some` value.
|
|
2062
|
+
*
|
|
1272
2063
|
* @since 2.0.0
|
|
1273
2064
|
* @category Creating Effects
|
|
1274
2065
|
*/
|
|
@@ -1276,6 +2067,8 @@ export const succeedNone = effect.succeedNone;
|
|
|
1276
2067
|
/**
|
|
1277
2068
|
* Returns an effect which succeeds with the value wrapped in a `Some`.
|
|
1278
2069
|
*
|
|
2070
|
+
* @see {@link succeedNone} for a similar function that returns `None` when the value is absent.
|
|
2071
|
+
*
|
|
1279
2072
|
* @since 2.0.0
|
|
1280
2073
|
* @category Creating Effects
|
|
1281
2074
|
*/
|
|
@@ -1283,16 +2076,28 @@ export const succeedSome = effect.succeedSome;
|
|
|
1283
2076
|
/**
|
|
1284
2077
|
* Delays the creation of an `Effect` until it is actually needed.
|
|
1285
2078
|
*
|
|
1286
|
-
* **
|
|
2079
|
+
* **Details**
|
|
1287
2080
|
*
|
|
1288
|
-
*
|
|
2081
|
+
* The `Effect.suspend` function takes a thunk that represents the effect and
|
|
2082
|
+
* wraps it in a suspended effect. This means the effect will not be created
|
|
2083
|
+
* until it is explicitly needed, which is helpful in various scenarios:
|
|
2084
|
+
* - **Lazy Evaluation**: Helps optimize performance by deferring computations,
|
|
2085
|
+
* especially when the effect might not be needed, or when its computation is
|
|
2086
|
+
* expensive. This also ensures that any side effects or scoped captures are
|
|
2087
|
+
* re-executed on each invocation.
|
|
2088
|
+
* - **Handling Circular Dependencies**: Useful in managing circular
|
|
2089
|
+
* dependencies, such as recursive functions that need to avoid eager
|
|
2090
|
+
* evaluation to prevent stack overflow.
|
|
2091
|
+
* - **Unifying Return Types**: Can help TypeScript unify return types in
|
|
2092
|
+
* situations where multiple branches of logic return different effects,
|
|
2093
|
+
* simplifying type inference.
|
|
1289
2094
|
*
|
|
1290
|
-
* **
|
|
2095
|
+
* **When to Use**
|
|
1291
2096
|
*
|
|
1292
|
-
*
|
|
1293
|
-
*
|
|
1294
|
-
*
|
|
1295
|
-
*
|
|
2097
|
+
* Use this function when you need to defer the evaluation of an effect until it
|
|
2098
|
+
* is required. This is particularly useful for optimizing expensive
|
|
2099
|
+
* computations, managing circular dependencies, or resolving type inference
|
|
2100
|
+
* issues.
|
|
1296
2101
|
*
|
|
1297
2102
|
* @example
|
|
1298
2103
|
* ```ts
|
|
@@ -1366,10 +2171,6 @@ export const suspend = core.suspend;
|
|
|
1366
2171
|
/**
|
|
1367
2172
|
* Creates an `Effect` that represents a synchronous side-effectful computation.
|
|
1368
2173
|
*
|
|
1369
|
-
* **When to Use**
|
|
1370
|
-
*
|
|
1371
|
-
* Use `sync` when you are sure the operation will not fail.
|
|
1372
|
-
*
|
|
1373
2174
|
* **Details**
|
|
1374
2175
|
*
|
|
1375
2176
|
* The provided function (`thunk`) must not throw errors; if it does, the error
|
|
@@ -1380,6 +2181,10 @@ export const suspend = core.suspend;
|
|
|
1380
2181
|
* crash in the program, which can be further managed or logged using tools like
|
|
1381
2182
|
* {@link catchAllDefect}.
|
|
1382
2183
|
*
|
|
2184
|
+
* **When to Use**
|
|
2185
|
+
*
|
|
2186
|
+
* Use this function when you are sure the operation will not fail.
|
|
2187
|
+
*
|
|
1383
2188
|
* @see {@link try_ | try} for a version that can handle failures.
|
|
1384
2189
|
*
|
|
1385
2190
|
* @example
|
|
@@ -1404,6 +2209,16 @@ export const sync = core.sync;
|
|
|
1404
2209
|
const _void = core.void;
|
|
1405
2210
|
export {
|
|
1406
2211
|
/**
|
|
2212
|
+
* Represents an effect that does nothing and produces no value.
|
|
2213
|
+
*
|
|
2214
|
+
* **When to Use**
|
|
2215
|
+
*
|
|
2216
|
+
* Use this effect when you need to represent an effect that does nothing.
|
|
2217
|
+
* This is useful in scenarios where you need to satisfy an effect-based
|
|
2218
|
+
* interface or control program flow without performing any operations. For
|
|
2219
|
+
* example, it can be used in situations where you want to return an effect
|
|
2220
|
+
* from a function but do not need to compute or return any result.
|
|
2221
|
+
*
|
|
1407
2222
|
* @since 2.0.0
|
|
1408
2223
|
* @category Creating Effects
|
|
1409
2224
|
*/
|
|
@@ -1416,7 +2231,45 @@ export const yieldNow = core.yieldNow;
|
|
|
1416
2231
|
const _catch = effect._catch;
|
|
1417
2232
|
export {
|
|
1418
2233
|
/**
|
|
1419
|
-
* Recovers from specified error.
|
|
2234
|
+
* Recovers from a specified error by catching it and handling it with a provided function.
|
|
2235
|
+
*
|
|
2236
|
+
* **Details**
|
|
2237
|
+
*
|
|
2238
|
+
* This function allows you to recover from specific errors that occur during
|
|
2239
|
+
* the execution of an effect. It works by catching a specific type of error
|
|
2240
|
+
* (identified by a discriminator) and then handling it using a provided
|
|
2241
|
+
* handler function. The handler can return a new effect that helps recover
|
|
2242
|
+
* from the error, allowing the program to continue. If the error doesn't
|
|
2243
|
+
* match the specified type, the function allows the original effect to
|
|
2244
|
+
* continue as it was.
|
|
2245
|
+
*
|
|
2246
|
+
* @see {@link catchTag} for a version that can recover from errors based on a `_tag` discriminator.
|
|
2247
|
+
*
|
|
2248
|
+
* @example
|
|
2249
|
+
* ```ts
|
|
2250
|
+
* import { Console, Effect } from "effect"
|
|
2251
|
+
*
|
|
2252
|
+
* class NetworkError {
|
|
2253
|
+
* readonly _tag = "NetworkError"
|
|
2254
|
+
* }
|
|
2255
|
+
* class ValidationError {
|
|
2256
|
+
* readonly _tag = "ValidationError"
|
|
2257
|
+
* }
|
|
2258
|
+
*
|
|
2259
|
+
* // Simulate an effect that may fail
|
|
2260
|
+
* const task: Effect.Effect<never, NetworkError | ValidationError, never> = Effect.fail(new NetworkError())
|
|
2261
|
+
*
|
|
2262
|
+
* const program = Effect.gen(function*() {
|
|
2263
|
+
* const result = yield* Effect.catch(task, "_tag", {
|
|
2264
|
+
* failure: "NetworkError",
|
|
2265
|
+
* onFailure: (error) => Effect.succeed(`recovered from error: ${error._tag}`)
|
|
2266
|
+
* })
|
|
2267
|
+
* console.log(`Result: ${result}`)
|
|
2268
|
+
* })
|
|
2269
|
+
*
|
|
2270
|
+
* Effect.runFork(program)
|
|
2271
|
+
* // Output: Result: recovered from error: NetworkError
|
|
2272
|
+
* ```
|
|
1420
2273
|
*
|
|
1421
2274
|
* @since 2.0.0
|
|
1422
2275
|
* @category Error handling
|
|
@@ -1427,15 +2280,16 @@ _catch as catch };
|
|
|
1427
2280
|
*
|
|
1428
2281
|
* **Details**
|
|
1429
2282
|
*
|
|
1430
|
-
*
|
|
1431
|
-
*
|
|
1432
|
-
*
|
|
1433
|
-
*
|
|
2283
|
+
* This function catches any errors that may occur during the execution of an
|
|
2284
|
+
* effect and allows you to handle them by specifying a fallback effect. This
|
|
2285
|
+
* ensures that the program continues without failing by recovering from errors
|
|
2286
|
+
* using the provided fallback logic.
|
|
1434
2287
|
*
|
|
1435
|
-
* **Note**:
|
|
2288
|
+
* **Note**: This function only handles recoverable errors. It will not recover
|
|
1436
2289
|
* from unrecoverable defects.
|
|
1437
2290
|
*
|
|
1438
|
-
* @see {@link catchAllCause} for a version that can recover from both
|
|
2291
|
+
* @see {@link catchAllCause} for a version that can recover from both
|
|
2292
|
+
* recoverable and unrecoverable errors.
|
|
1439
2293
|
*
|
|
1440
2294
|
* @example
|
|
1441
2295
|
* ```ts
|
|
@@ -1914,12 +2768,15 @@ export const eventually = effect.eventually;
|
|
|
1914
2768
|
/**
|
|
1915
2769
|
* Discards both the success and failure values of an effect.
|
|
1916
2770
|
*
|
|
1917
|
-
*
|
|
1918
|
-
*
|
|
1919
|
-
*
|
|
2771
|
+
* **When to Use**
|
|
2772
|
+
*
|
|
2773
|
+
* `ignore` allows you to run an effect without caring about its result, whether
|
|
2774
|
+
* it succeeds or fails. This is useful when you only care about the side
|
|
2775
|
+
* effects of the effect and do not need to handle or process its outcome.
|
|
1920
2776
|
*
|
|
1921
2777
|
* @example
|
|
1922
2778
|
* ```ts
|
|
2779
|
+
* // Title: Using Effect.ignore to Discard Values
|
|
1923
2780
|
* import { Effect } from "effect"
|
|
1924
2781
|
*
|
|
1925
2782
|
* // ┌─── Effect<number, string, never>
|
|
@@ -2040,21 +2897,30 @@ export const sandbox = effect.sandbox;
|
|
|
2040
2897
|
/**
|
|
2041
2898
|
* Retries a failing effect based on a defined retry policy.
|
|
2042
2899
|
*
|
|
2043
|
-
*
|
|
2044
|
-
*
|
|
2045
|
-
*
|
|
2046
|
-
*
|
|
2047
|
-
*
|
|
2900
|
+
* **Details**
|
|
2901
|
+
*
|
|
2902
|
+
* The `Effect.retry` function takes an effect and a {@link Schedule} policy,
|
|
2903
|
+
* and will automatically retry the effect if it fails, following the rules of
|
|
2904
|
+
* the policy.
|
|
2905
|
+
*
|
|
2906
|
+
* If the effect ultimately succeeds, the result will be returned.
|
|
2907
|
+
*
|
|
2908
|
+
* If the maximum retries are exhausted and the effect still fails, the failure
|
|
2909
|
+
* is propagated.
|
|
2910
|
+
*
|
|
2911
|
+
* **When to Use**
|
|
2048
2912
|
*
|
|
2049
|
-
*
|
|
2050
|
-
*
|
|
2051
|
-
*
|
|
2052
|
-
*
|
|
2913
|
+
* This can be useful when dealing with intermittent failures, such as network
|
|
2914
|
+
* issues or temporary resource unavailability. By defining a retry policy, you
|
|
2915
|
+
* can control the number of retries, the delay between them, and when to stop
|
|
2916
|
+
* retrying.
|
|
2053
2917
|
*
|
|
2054
2918
|
* @see {@link retryOrElse} for a version that allows you to run a fallback.
|
|
2919
|
+
* @see {@link repeat} if your retry condition is based on successful outcomes rather than errors.
|
|
2055
2920
|
*
|
|
2056
2921
|
* @example
|
|
2057
2922
|
* ```ts
|
|
2923
|
+
* // Title: Retrying with a Fixed Delay
|
|
2058
2924
|
* import { Effect, Schedule } from "effect"
|
|
2059
2925
|
*
|
|
2060
2926
|
* let count = 0
|
|
@@ -2076,13 +2942,71 @@ export const sandbox = effect.sandbox;
|
|
|
2076
2942
|
*
|
|
2077
2943
|
* const repeated = Effect.retry(task, policy)
|
|
2078
2944
|
*
|
|
2079
|
-
* Effect.runPromise(repeated).then(console.log)
|
|
2945
|
+
* Effect.runPromise(repeated).then(console.log)
|
|
2946
|
+
* // Output:
|
|
2947
|
+
* // failure
|
|
2948
|
+
* // failure
|
|
2949
|
+
* // failure
|
|
2950
|
+
* // success
|
|
2951
|
+
* // yay!
|
|
2952
|
+
* ```
|
|
2953
|
+
*
|
|
2954
|
+
* @example
|
|
2955
|
+
* ```ts
|
|
2956
|
+
* // Title: Retrying a Task up to 5 times
|
|
2957
|
+
* import { Effect } from "effect"
|
|
2958
|
+
*
|
|
2959
|
+
* let count = 0
|
|
2960
|
+
*
|
|
2961
|
+
* // Simulates an effect with possible failures
|
|
2962
|
+
* const task = Effect.async<string, Error>((resume) => {
|
|
2963
|
+
* if (count <= 2) {
|
|
2964
|
+
* count++
|
|
2965
|
+
* console.log("failure")
|
|
2966
|
+
* resume(Effect.fail(new Error()))
|
|
2967
|
+
* } else {
|
|
2968
|
+
* console.log("success")
|
|
2969
|
+
* resume(Effect.succeed("yay!"))
|
|
2970
|
+
* }
|
|
2971
|
+
* })
|
|
2972
|
+
*
|
|
2973
|
+
* // Retry the task up to 5 times
|
|
2974
|
+
* Effect.runPromise(Effect.retry(task, { times: 5 }))
|
|
2080
2975
|
* // Output:
|
|
2081
2976
|
* // failure
|
|
2082
2977
|
* // failure
|
|
2083
2978
|
* // failure
|
|
2084
2979
|
* // success
|
|
2085
|
-
*
|
|
2980
|
+
* ```
|
|
2981
|
+
*
|
|
2982
|
+
* @example
|
|
2983
|
+
* ```ts
|
|
2984
|
+
* // Title: Retrying Until a Specific Condition is Met
|
|
2985
|
+
* import { Effect } from "effect"
|
|
2986
|
+
*
|
|
2987
|
+
* let count = 0
|
|
2988
|
+
*
|
|
2989
|
+
* // Define an effect that simulates varying error on each invocation
|
|
2990
|
+
* const action = Effect.failSync(() => {
|
|
2991
|
+
* console.log(`Action called ${++count} time(s)`)
|
|
2992
|
+
* return `Error ${count}`
|
|
2993
|
+
* })
|
|
2994
|
+
*
|
|
2995
|
+
* // Retry the action until a specific condition is met
|
|
2996
|
+
* const program = Effect.retry(action, {
|
|
2997
|
+
* until: (err) => err === "Error 3"
|
|
2998
|
+
* })
|
|
2999
|
+
*
|
|
3000
|
+
* Effect.runPromiseExit(program).then(console.log)
|
|
3001
|
+
* // Output:
|
|
3002
|
+
* // Action called 1 time(s)
|
|
3003
|
+
* // Action called 2 time(s)
|
|
3004
|
+
* // Action called 3 time(s)
|
|
3005
|
+
* // {
|
|
3006
|
+
* // _id: 'Exit',
|
|
3007
|
+
* // _tag: 'Failure',
|
|
3008
|
+
* // cause: { _id: 'Cause', _tag: 'Fail', failure: 'Error 3' }
|
|
3009
|
+
* // }
|
|
2086
3010
|
* ```
|
|
2087
3011
|
*
|
|
2088
3012
|
* @since 2.0.0
|
|
@@ -2092,16 +3016,24 @@ export const retry = _schedule.retry_combined;
|
|
|
2092
3016
|
/**
|
|
2093
3017
|
* Retries a failing effect and runs a fallback effect if retries are exhausted.
|
|
2094
3018
|
*
|
|
2095
|
-
*
|
|
2096
|
-
*
|
|
2097
|
-
*
|
|
2098
|
-
*
|
|
2099
|
-
*
|
|
3019
|
+
* **Details**
|
|
3020
|
+
*
|
|
3021
|
+
* The `Effect.retryOrElse` function attempts to retry a failing effect multiple
|
|
3022
|
+
* times according to a defined {@link Schedule} policy.
|
|
3023
|
+
*
|
|
3024
|
+
* If the retries are exhausted and the effect still fails, it runs a fallback
|
|
3025
|
+
* effect instead.
|
|
3026
|
+
*
|
|
3027
|
+
* **When to Use**
|
|
3028
|
+
*
|
|
3029
|
+
* This function is useful when you want to handle failures gracefully by
|
|
3030
|
+
* specifying an alternative action after repeated failures.
|
|
2100
3031
|
*
|
|
2101
3032
|
* @see {@link retry} for a version that does not run a fallback effect.
|
|
2102
3033
|
*
|
|
2103
3034
|
* @example
|
|
2104
3035
|
* ```ts
|
|
3036
|
+
* // Title: Retrying with Fallback
|
|
2105
3037
|
* import { Effect, Schedule, Console } from "effect"
|
|
2106
3038
|
*
|
|
2107
3039
|
* let count = 0
|
|
@@ -2122,8 +3054,11 @@ export const retry = _schedule.retry_combined;
|
|
|
2122
3054
|
* const policy = Schedule.addDelay(Schedule.recurs(2), () => "100 millis")
|
|
2123
3055
|
*
|
|
2124
3056
|
* // If all retries fail, run the fallback effect
|
|
2125
|
-
* const repeated = Effect.retryOrElse(
|
|
2126
|
-
*
|
|
3057
|
+
* const repeated = Effect.retryOrElse(
|
|
3058
|
+
* task,
|
|
3059
|
+
* policy,
|
|
3060
|
+
* // fallback
|
|
3061
|
+
* () => Console.log("orElse").pipe(Effect.as("default value"))
|
|
2127
3062
|
* )
|
|
2128
3063
|
*
|
|
2129
3064
|
* Effect.runPromise(repeated).then(console.log)
|
|
@@ -2340,8 +3275,8 @@ export const checkInterruptible = core.checkInterruptible;
|
|
|
2340
3275
|
* error or trigger alternative logic. This enables faster timeout handling
|
|
2341
3276
|
* without waiting for the completion of the long-running task.
|
|
2342
3277
|
*
|
|
2343
|
-
* @see {@link
|
|
2344
|
-
* @see {@link
|
|
3278
|
+
* @see {@link timeout} for a version that interrupts the effect.
|
|
3279
|
+
* @see {@link uninterruptible} for creating an uninterruptible effect.
|
|
2345
3280
|
*
|
|
2346
3281
|
* @example
|
|
2347
3282
|
* ```ts
|
|
@@ -4229,160 +5164,572 @@ export const whenRef = effect.whenRef;
|
|
|
4229
5164
|
* specifically with `Effect` instances, allowing you to avoid deeply nested
|
|
4230
5165
|
* effect structures.
|
|
4231
5166
|
*
|
|
4232
|
-
* Since effects are immutable, `flatMap` always returns a new effect instead of
|
|
4233
|
-
* changing the original one.
|
|
5167
|
+
* Since effects are immutable, `flatMap` always returns a new effect instead of
|
|
5168
|
+
* changing the original one.
|
|
5169
|
+
*
|
|
5170
|
+
* @example
|
|
5171
|
+
* ```ts
|
|
5172
|
+
* import { pipe, Effect } from "effect"
|
|
5173
|
+
*
|
|
5174
|
+
* // Function to apply a discount safely to a transaction amount
|
|
5175
|
+
* const applyDiscount = (
|
|
5176
|
+
* total: number,
|
|
5177
|
+
* discountRate: number
|
|
5178
|
+
* ): Effect.Effect<number, Error> =>
|
|
5179
|
+
* discountRate === 0
|
|
5180
|
+
* ? Effect.fail(new Error("Discount rate cannot be zero"))
|
|
5181
|
+
* : Effect.succeed(total - (total * discountRate) / 100)
|
|
5182
|
+
*
|
|
5183
|
+
* // Simulated asynchronous task to fetch a transaction amount from database
|
|
5184
|
+
* const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
|
|
5185
|
+
*
|
|
5186
|
+
* // Chaining the fetch and discount application using `flatMap`
|
|
5187
|
+
* const finalAmount = pipe(
|
|
5188
|
+
* fetchTransactionAmount,
|
|
5189
|
+
* Effect.flatMap((amount) => applyDiscount(amount, 5))
|
|
5190
|
+
* )
|
|
5191
|
+
*
|
|
5192
|
+
* Effect.runPromise(finalAmount).then(console.log)
|
|
5193
|
+
* // Output: 95
|
|
5194
|
+
* ```
|
|
5195
|
+
*
|
|
5196
|
+
* @since 2.0.0
|
|
5197
|
+
* @category sequencing
|
|
5198
|
+
*/
|
|
5199
|
+
export const flatMap = core.flatMap;
|
|
5200
|
+
/**
|
|
5201
|
+
* Chains two actions, where the second action can depend on the result of the
|
|
5202
|
+
* first.
|
|
5203
|
+
*
|
|
5204
|
+
* **Syntax**
|
|
5205
|
+
* ```ts
|
|
5206
|
+
* const transformedEffect = pipe(myEffect, Effect.andThen(anotherEffect))
|
|
5207
|
+
* // or
|
|
5208
|
+
* const transformedEffect = Effect.andThen(myEffect, anotherEffect)
|
|
5209
|
+
* // or
|
|
5210
|
+
* const transformedEffect = myEffect.pipe(Effect.andThen(anotherEffect))
|
|
5211
|
+
* ```
|
|
5212
|
+
*
|
|
5213
|
+
* **When to Use**
|
|
5214
|
+
*
|
|
5215
|
+
* Use `andThen` when you need to run multiple actions in sequence, with the
|
|
5216
|
+
* second action depending on the result of the first. This is useful for
|
|
5217
|
+
* combining effects or handling computations that must happen in order.
|
|
5218
|
+
*
|
|
5219
|
+
* **Details**
|
|
5220
|
+
*
|
|
5221
|
+
* The second action can be:
|
|
5222
|
+
*
|
|
5223
|
+
* - A constant value (similar to {@link as})
|
|
5224
|
+
* - A function returning a value (similar to {@link map})
|
|
5225
|
+
* - A `Promise`
|
|
5226
|
+
* - A function returning a `Promise`
|
|
5227
|
+
* - An `Effect`
|
|
5228
|
+
* - A function returning an `Effect` (similar to {@link flatMap})
|
|
5229
|
+
*
|
|
5230
|
+
* **Note:** `andThen` works well with both `Option` and `Either` types,
|
|
5231
|
+
* treating them as effects.
|
|
5232
|
+
*
|
|
5233
|
+
* @example
|
|
5234
|
+
* ```ts
|
|
5235
|
+
* // Title: Applying a Discount Based on Fetched Amount
|
|
5236
|
+
* import { pipe, Effect } from "effect"
|
|
5237
|
+
*
|
|
5238
|
+
* // Function to apply a discount safely to a transaction amount
|
|
5239
|
+
* const applyDiscount = (
|
|
5240
|
+
* total: number,
|
|
5241
|
+
* discountRate: number
|
|
5242
|
+
* ): Effect.Effect<number, Error> =>
|
|
5243
|
+
* discountRate === 0
|
|
5244
|
+
* ? Effect.fail(new Error("Discount rate cannot be zero"))
|
|
5245
|
+
* : Effect.succeed(total - (total * discountRate) / 100)
|
|
5246
|
+
*
|
|
5247
|
+
* // Simulated asynchronous task to fetch a transaction amount from database
|
|
5248
|
+
* const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100))
|
|
5249
|
+
*
|
|
5250
|
+
* // Using Effect.map and Effect.flatMap
|
|
5251
|
+
* const result1 = pipe(
|
|
5252
|
+
* fetchTransactionAmount,
|
|
5253
|
+
* Effect.map((amount) => amount * 2),
|
|
5254
|
+
* Effect.flatMap((amount) => applyDiscount(amount, 5))
|
|
5255
|
+
* )
|
|
5256
|
+
*
|
|
5257
|
+
* Effect.runPromise(result1).then(console.log)
|
|
5258
|
+
* // Output: 190
|
|
5259
|
+
*
|
|
5260
|
+
* // Using Effect.andThen
|
|
5261
|
+
* const result2 = pipe(
|
|
5262
|
+
* fetchTransactionAmount,
|
|
5263
|
+
* Effect.andThen((amount) => amount * 2),
|
|
5264
|
+
* Effect.andThen((amount) => applyDiscount(amount, 5))
|
|
5265
|
+
* )
|
|
5266
|
+
*
|
|
5267
|
+
* Effect.runPromise(result2).then(console.log)
|
|
5268
|
+
* // Output: 190
|
|
5269
|
+
* ```
|
|
5270
|
+
*
|
|
5271
|
+
* @since 2.0.0
|
|
5272
|
+
* @category sequencing
|
|
5273
|
+
*/
|
|
5274
|
+
export const andThen = core.andThen;
|
|
5275
|
+
/**
|
|
5276
|
+
* @since 2.0.0
|
|
5277
|
+
* @category sequencing
|
|
5278
|
+
*/
|
|
5279
|
+
export const flatten = core.flatten;
|
|
5280
|
+
/**
|
|
5281
|
+
* Races two effects and returns the result of the first successful one.
|
|
5282
|
+
*
|
|
5283
|
+
* **Details**
|
|
5284
|
+
*
|
|
5285
|
+
* This function takes two effects and runs them concurrently. The first effect
|
|
5286
|
+
* that successfully completes will determine the result of the race, and the
|
|
5287
|
+
* other effect will be interrupted.
|
|
5288
|
+
*
|
|
5289
|
+
* If neither effect succeeds, the function will fail with a `Cause`
|
|
5290
|
+
* containing all the errors.
|
|
5291
|
+
*
|
|
5292
|
+
* **When to Use**
|
|
5293
|
+
*
|
|
5294
|
+
* This is useful when you want to run two effects concurrently, but only care
|
|
5295
|
+
* about the first one to succeed. It is commonly used in cases like timeouts,
|
|
5296
|
+
* retries, or when you want to optimize for the faster response without
|
|
5297
|
+
* worrying about the other effect.
|
|
5298
|
+
*
|
|
5299
|
+
* **Handling Success or Failure with Either**
|
|
5300
|
+
*
|
|
5301
|
+
* If you want to handle the result of whichever task completes first, whether
|
|
5302
|
+
* it succeeds or fails, you can use the `Effect.either` function. This function
|
|
5303
|
+
* wraps the result in an `Either` type, allowing you to see if the result
|
|
5304
|
+
* was a success (`Right`) or a failure (`Left`).
|
|
5305
|
+
*
|
|
5306
|
+
* @see {@link raceAll} for a version that handles multiple effects.
|
|
5307
|
+
* @see {@link raceFirst} for a version that returns the result of the first effect to complete.
|
|
5308
|
+
*
|
|
5309
|
+
* @example
|
|
5310
|
+
* ```ts
|
|
5311
|
+
* // Title: Both Tasks Succeed
|
|
5312
|
+
* import { Effect, Console } from "effect"
|
|
5313
|
+
*
|
|
5314
|
+
* const task1 = Effect.succeed("task1").pipe(
|
|
5315
|
+
* Effect.delay("200 millis"),
|
|
5316
|
+
* Effect.tap(Console.log("task1 done")),
|
|
5317
|
+
* Effect.onInterrupt(() => Console.log("task1 interrupted"))
|
|
5318
|
+
* )
|
|
5319
|
+
* const task2 = Effect.succeed("task2").pipe(
|
|
5320
|
+
* Effect.delay("100 millis"),
|
|
5321
|
+
* Effect.tap(Console.log("task2 done")),
|
|
5322
|
+
* Effect.onInterrupt(() => Console.log("task2 interrupted"))
|
|
5323
|
+
* )
|
|
5324
|
+
*
|
|
5325
|
+
* const program = Effect.race(task1, task2)
|
|
5326
|
+
*
|
|
5327
|
+
* Effect.runFork(program)
|
|
5328
|
+
* // Output:
|
|
5329
|
+
* // task1 done
|
|
5330
|
+
* // task2 interrupted
|
|
5331
|
+
* ```
|
|
5332
|
+
*
|
|
5333
|
+
* @example
|
|
5334
|
+
* ```ts
|
|
5335
|
+
* // Title: One Task Fails, One Succeeds
|
|
5336
|
+
* import { Effect, Console } from "effect"
|
|
5337
|
+
*
|
|
5338
|
+
* const task1 = Effect.fail("task1").pipe(
|
|
5339
|
+
* Effect.delay("100 millis"),
|
|
5340
|
+
* Effect.tap(Console.log("task1 done")),
|
|
5341
|
+
* Effect.onInterrupt(() => Console.log("task1 interrupted"))
|
|
5342
|
+
* )
|
|
5343
|
+
* const task2 = Effect.succeed("task2").pipe(
|
|
5344
|
+
* Effect.delay("200 millis"),
|
|
5345
|
+
* Effect.tap(Console.log("task2 done")),
|
|
5346
|
+
* Effect.onInterrupt(() => Console.log("task2 interrupted"))
|
|
5347
|
+
* )
|
|
5348
|
+
*
|
|
5349
|
+
* const program = Effect.race(task1, task2)
|
|
5350
|
+
*
|
|
5351
|
+
* Effect.runFork(program)
|
|
5352
|
+
* // Output:
|
|
5353
|
+
* // task2 done
|
|
5354
|
+
* ```
|
|
5355
|
+
*
|
|
5356
|
+
* @example
|
|
5357
|
+
* ```ts
|
|
5358
|
+
* // Title: Both Tasks Fail
|
|
5359
|
+
* import { Effect, Console } from "effect"
|
|
5360
|
+
*
|
|
5361
|
+
* const task1 = Effect.fail("task1").pipe(
|
|
5362
|
+
* Effect.delay("100 millis"),
|
|
5363
|
+
* Effect.tap(Console.log("task1 done")),
|
|
5364
|
+
* Effect.onInterrupt(() => Console.log("task1 interrupted"))
|
|
5365
|
+
* )
|
|
5366
|
+
* const task2 = Effect.fail("task2").pipe(
|
|
5367
|
+
* Effect.delay("200 millis"),
|
|
5368
|
+
* Effect.tap(Console.log("task2 done")),
|
|
5369
|
+
* Effect.onInterrupt(() => Console.log("task2 interrupted"))
|
|
5370
|
+
* )
|
|
5371
|
+
*
|
|
5372
|
+
* const program = Effect.race(task1, task2)
|
|
5373
|
+
*
|
|
5374
|
+
* Effect.runPromiseExit(program).then(console.log)
|
|
5375
|
+
* // Output:
|
|
5376
|
+
* // {
|
|
5377
|
+
* // _id: 'Exit',
|
|
5378
|
+
* // _tag: 'Failure',
|
|
5379
|
+
* // cause: {
|
|
5380
|
+
* // _id: 'Cause',
|
|
5381
|
+
* // _tag: 'Parallel',
|
|
5382
|
+
* // left: { _id: 'Cause', _tag: 'Fail', failure: 'task1' },
|
|
5383
|
+
* // right: { _id: 'Cause', _tag: 'Fail', failure: 'task2' }
|
|
5384
|
+
* // }
|
|
5385
|
+
* // }
|
|
5386
|
+
* ```
|
|
5387
|
+
*
|
|
5388
|
+
* @example
|
|
5389
|
+
* ```ts
|
|
5390
|
+
* // Title: Handling Success or Failure with Either
|
|
5391
|
+
* import { Effect, Console } from "effect"
|
|
5392
|
+
*
|
|
5393
|
+
* const task1 = Effect.fail("task1").pipe(
|
|
5394
|
+
* Effect.delay("100 millis"),
|
|
5395
|
+
* Effect.tap(Console.log("task1 done")),
|
|
5396
|
+
* Effect.onInterrupt(() => Console.log("task1 interrupted"))
|
|
5397
|
+
* )
|
|
5398
|
+
* const task2 = Effect.succeed("task2").pipe(
|
|
5399
|
+
* Effect.delay("200 millis"),
|
|
5400
|
+
* Effect.tap(Console.log("task2 done")),
|
|
5401
|
+
* Effect.onInterrupt(() => Console.log("task2 interrupted"))
|
|
5402
|
+
* )
|
|
5403
|
+
*
|
|
5404
|
+
* // Run both tasks concurrently, wrapping the result
|
|
5405
|
+
* // in Either to capture success or failure
|
|
5406
|
+
* const program = Effect.race(Effect.either(task1), Effect.either(task2))
|
|
5407
|
+
*
|
|
5408
|
+
* Effect.runPromise(program).then(console.log)
|
|
5409
|
+
* // Output:
|
|
5410
|
+
* // task2 interrupted
|
|
5411
|
+
* // { _id: 'Either', _tag: 'Left', left: 'task1' }
|
|
5412
|
+
* ```
|
|
5413
|
+
*
|
|
5414
|
+
* @since 2.0.0
|
|
5415
|
+
* @category Racing
|
|
5416
|
+
*/
|
|
5417
|
+
export const race = fiberRuntime.race;
|
|
5418
|
+
/**
|
|
5419
|
+
* Races multiple effects and returns the first successful result.
|
|
5420
|
+
*
|
|
5421
|
+
* **Details**
|
|
5422
|
+
*
|
|
5423
|
+
* This function runs multiple effects concurrently and returns the result of
|
|
5424
|
+
* the first one to succeed. If one effect succeeds, the others will be
|
|
5425
|
+
* interrupted.
|
|
5426
|
+
*
|
|
5427
|
+
* If none of the effects succeed, the function will fail with the last error
|
|
5428
|
+
* encountered.
|
|
5429
|
+
*
|
|
5430
|
+
* **When to Use**
|
|
5431
|
+
*
|
|
5432
|
+
* This is useful when you want to race multiple effects, but only care about
|
|
5433
|
+
* the first one to succeed. It is commonly used in cases like timeouts,
|
|
5434
|
+
* retries, or when you want to optimize for the faster response without
|
|
5435
|
+
* worrying about the other effects.
|
|
5436
|
+
*
|
|
5437
|
+
* @see {@link race} for a version that handles only two effects.
|
|
5438
|
+
*
|
|
5439
|
+
* @example
|
|
5440
|
+
* ```ts
|
|
5441
|
+
* // Title: All Tasks Succeed
|
|
5442
|
+
* import { Effect, Console } from "effect"
|
|
5443
|
+
*
|
|
5444
|
+
* const task1 = Effect.succeed("task1").pipe(
|
|
5445
|
+
* Effect.delay("100 millis"),
|
|
5446
|
+
* Effect.tap(Console.log("task1 done")),
|
|
5447
|
+
* Effect.onInterrupt(() => Console.log("task1 interrupted"))
|
|
5448
|
+
* )
|
|
5449
|
+
* const task2 = Effect.succeed("task2").pipe(
|
|
5450
|
+
* Effect.delay("200 millis"),
|
|
5451
|
+
* Effect.tap(Console.log("task2 done")),
|
|
5452
|
+
* Effect.onInterrupt(() => Console.log("task2 interrupted"))
|
|
5453
|
+
* )
|
|
5454
|
+
*
|
|
5455
|
+
* const task3 = Effect.succeed("task3").pipe(
|
|
5456
|
+
* Effect.delay("150 millis"),
|
|
5457
|
+
* Effect.tap(Console.log("task3 done")),
|
|
5458
|
+
* Effect.onInterrupt(() => Console.log("task3 interrupted"))
|
|
5459
|
+
* )
|
|
5460
|
+
*
|
|
5461
|
+
* const program = Effect.raceAll([task1, task2, task3])
|
|
5462
|
+
*
|
|
5463
|
+
* Effect.runFork(program)
|
|
5464
|
+
* // Output:
|
|
5465
|
+
* // task1 done
|
|
5466
|
+
* // task2 interrupted
|
|
5467
|
+
* // task3 interrupted
|
|
5468
|
+
* ```
|
|
5469
|
+
*
|
|
5470
|
+
* @example
|
|
5471
|
+
* ```ts
|
|
5472
|
+
* // Title: One Task Fails, Two Tasks Succeed
|
|
5473
|
+
* import { Effect, Console } from "effect"
|
|
5474
|
+
*
|
|
5475
|
+
* const task1 = Effect.fail("task1").pipe(
|
|
5476
|
+
* Effect.delay("100 millis"),
|
|
5477
|
+
* Effect.tap(Console.log("task1 done")),
|
|
5478
|
+
* Effect.onInterrupt(() => Console.log("task1 interrupted"))
|
|
5479
|
+
* )
|
|
5480
|
+
* const task2 = Effect.succeed("task2").pipe(
|
|
5481
|
+
* Effect.delay("200 millis"),
|
|
5482
|
+
* Effect.tap(Console.log("task2 done")),
|
|
5483
|
+
* Effect.onInterrupt(() => Console.log("task2 interrupted"))
|
|
5484
|
+
* )
|
|
5485
|
+
*
|
|
5486
|
+
* const task3 = Effect.succeed("task3").pipe(
|
|
5487
|
+
* Effect.delay("150 millis"),
|
|
5488
|
+
* Effect.tap(Console.log("task3 done")),
|
|
5489
|
+
* Effect.onInterrupt(() => Console.log("task3 interrupted"))
|
|
5490
|
+
* )
|
|
5491
|
+
*
|
|
5492
|
+
* const program = Effect.raceAll([task1, task2, task3])
|
|
5493
|
+
*
|
|
5494
|
+
* Effect.runFork(program)
|
|
5495
|
+
* // Output:
|
|
5496
|
+
* // task3 done
|
|
5497
|
+
* // task2 interrupted
|
|
5498
|
+
* ```
|
|
4234
5499
|
*
|
|
4235
5500
|
* @example
|
|
4236
5501
|
* ```ts
|
|
4237
|
-
*
|
|
4238
|
-
*
|
|
4239
|
-
* // Function to apply a discount safely to a transaction amount
|
|
4240
|
-
* const applyDiscount = (
|
|
4241
|
-
* total: number,
|
|
4242
|
-
* discountRate: number
|
|
4243
|
-
* ): Effect.Effect<number, Error> =>
|
|
4244
|
-
* discountRate === 0
|
|
4245
|
-
* ? Effect.fail(new Error("Discount rate cannot be zero"))
|
|
4246
|
-
* : Effect.succeed(total - (total * discountRate) / 100)
|
|
5502
|
+
* // Title: All Tasks Fail
|
|
5503
|
+
* import { Effect, Console } from "effect"
|
|
4247
5504
|
*
|
|
4248
|
-
*
|
|
4249
|
-
*
|
|
5505
|
+
* const task1 = Effect.fail("task1").pipe(
|
|
5506
|
+
* Effect.delay("100 millis"),
|
|
5507
|
+
* Effect.tap(Console.log("task1 done")),
|
|
5508
|
+
* Effect.onInterrupt(() => Console.log("task1 interrupted"))
|
|
5509
|
+
* )
|
|
5510
|
+
* const task2 = Effect.fail("task2").pipe(
|
|
5511
|
+
* Effect.delay("200 millis"),
|
|
5512
|
+
* Effect.tap(Console.log("task2 done")),
|
|
5513
|
+
* Effect.onInterrupt(() => Console.log("task2 interrupted"))
|
|
5514
|
+
* )
|
|
4250
5515
|
*
|
|
4251
|
-
*
|
|
4252
|
-
*
|
|
4253
|
-
*
|
|
4254
|
-
* Effect.
|
|
5516
|
+
* const task3 = Effect.fail("task3").pipe(
|
|
5517
|
+
* Effect.delay("150 millis"),
|
|
5518
|
+
* Effect.tap(Console.log("task3 done")),
|
|
5519
|
+
* Effect.onInterrupt(() => Console.log("task3 interrupted"))
|
|
4255
5520
|
* )
|
|
4256
5521
|
*
|
|
4257
|
-
* Effect.
|
|
4258
|
-
*
|
|
5522
|
+
* const program = Effect.raceAll([task1, task2, task3])
|
|
5523
|
+
*
|
|
5524
|
+
* Effect.runPromiseExit(program).then(console.log)
|
|
5525
|
+
* // Output:
|
|
5526
|
+
* // {
|
|
5527
|
+
* // _id: 'Exit',
|
|
5528
|
+
* // _tag: 'Failure',
|
|
5529
|
+
* // cause: { _id: 'Cause', _tag: 'Fail', failure: 'task2' }
|
|
5530
|
+
* // }
|
|
4259
5531
|
* ```
|
|
4260
5532
|
*
|
|
4261
5533
|
* @since 2.0.0
|
|
4262
|
-
* @category
|
|
5534
|
+
* @category Racing
|
|
4263
5535
|
*/
|
|
4264
|
-
export const
|
|
5536
|
+
export const raceAll = fiberRuntime.raceAll;
|
|
4265
5537
|
/**
|
|
4266
|
-
*
|
|
4267
|
-
* first.
|
|
5538
|
+
* Races two effects and returns the result of the first one to complete.
|
|
4268
5539
|
*
|
|
4269
|
-
* **
|
|
4270
|
-
*
|
|
4271
|
-
*
|
|
4272
|
-
*
|
|
4273
|
-
*
|
|
4274
|
-
* // or
|
|
4275
|
-
* const transformedEffect = myEffect.pipe(Effect.andThen(anotherEffect))
|
|
4276
|
-
* ```
|
|
5540
|
+
* **Details**
|
|
5541
|
+
*
|
|
5542
|
+
* This function takes two effects and runs them concurrently, returning the
|
|
5543
|
+
* result of the first one that completes, regardless of whether it succeeds or
|
|
5544
|
+
* fails.
|
|
4277
5545
|
*
|
|
4278
5546
|
* **When to Use**
|
|
4279
5547
|
*
|
|
4280
|
-
*
|
|
4281
|
-
*
|
|
4282
|
-
*
|
|
5548
|
+
* This function is useful when you want to race two operations, and you want to
|
|
5549
|
+
* proceed with whichever one finishes first, regardless of whether it succeeds
|
|
5550
|
+
* or fails.
|
|
4283
5551
|
*
|
|
4284
|
-
* **
|
|
5552
|
+
* **Disconnecting Effects**
|
|
4285
5553
|
*
|
|
4286
|
-
* The
|
|
5554
|
+
* The `Effect.raceFirst` function safely interrupts the “loser” effect once the other completes, but it will not resume until the loser is cleanly terminated.
|
|
4287
5555
|
*
|
|
4288
|
-
*
|
|
4289
|
-
* - A function returning a value (similar to {@link map})
|
|
4290
|
-
* - A `Promise`
|
|
4291
|
-
* - A function returning a `Promise`
|
|
4292
|
-
* - An `Effect`
|
|
4293
|
-
* - A function returning an `Effect` (similar to {@link flatMap})
|
|
5556
|
+
* If you want a quicker return, you can disconnect the interrupt signal for both effects. Instead of calling:
|
|
4294
5557
|
*
|
|
4295
|
-
*
|
|
4296
|
-
*
|
|
5558
|
+
* ```ts
|
|
5559
|
+
* Effect.raceFirst(task1, task2)
|
|
5560
|
+
* ```
|
|
5561
|
+
*
|
|
5562
|
+
* You can use:
|
|
4297
5563
|
*
|
|
4298
|
-
* @example
|
|
4299
5564
|
* ```ts
|
|
4300
|
-
*
|
|
4301
|
-
*
|
|
5565
|
+
* Effect.raceFirst(Effect.disconnect(task1), Effect.disconnect(task2))
|
|
5566
|
+
* ```
|
|
4302
5567
|
*
|
|
4303
|
-
*
|
|
4304
|
-
* const applyDiscount = (
|
|
4305
|
-
* total: number,
|
|
4306
|
-
* discountRate: number
|
|
4307
|
-
* ): Effect.Effect<number, Error> =>
|
|
4308
|
-
* discountRate === 0
|
|
4309
|
-
* ? Effect.fail(new Error("Discount rate cannot be zero"))
|
|
4310
|
-
* : Effect.succeed(total - (total * discountRate) / 100)
|
|
5568
|
+
* This allows both effects to complete independently while still terminating the losing effect in the background.
|
|
4311
5569
|
*
|
|
4312
|
-
*
|
|
4313
|
-
*
|
|
5570
|
+
* @example
|
|
5571
|
+
* ```ts
|
|
5572
|
+
* // Title: Both Tasks Succeed
|
|
5573
|
+
* import { Effect, Console } from "effect"
|
|
4314
5574
|
*
|
|
4315
|
-
*
|
|
4316
|
-
*
|
|
4317
|
-
*
|
|
4318
|
-
* Effect.
|
|
4319
|
-
*
|
|
5575
|
+
* const task1 = Effect.succeed("task1").pipe(
|
|
5576
|
+
* Effect.delay("100 millis"),
|
|
5577
|
+
* Effect.tap(Console.log("task1 done")),
|
|
5578
|
+
* Effect.onInterrupt(() =>
|
|
5579
|
+
* Console.log("task1 interrupted").pipe(Effect.delay("100 millis"))
|
|
5580
|
+
* )
|
|
5581
|
+
* )
|
|
5582
|
+
* const task2 = Effect.succeed("task2").pipe(
|
|
5583
|
+
* Effect.delay("200 millis"),
|
|
5584
|
+
* Effect.tap(Console.log("task2 done")),
|
|
5585
|
+
* Effect.onInterrupt(() =>
|
|
5586
|
+
* Console.log("task2 interrupted").pipe(Effect.delay("100 millis"))
|
|
5587
|
+
* )
|
|
4320
5588
|
* )
|
|
4321
5589
|
*
|
|
4322
|
-
* Effect.
|
|
4323
|
-
*
|
|
5590
|
+
* const program = Effect.raceFirst(task1, task2).pipe(
|
|
5591
|
+
* Effect.tap(Console.log("more work..."))
|
|
5592
|
+
* )
|
|
4324
5593
|
*
|
|
4325
|
-
*
|
|
4326
|
-
*
|
|
4327
|
-
*
|
|
4328
|
-
*
|
|
4329
|
-
*
|
|
5594
|
+
* Effect.runPromiseExit(program).then(console.log)
|
|
5595
|
+
* // Output:
|
|
5596
|
+
* // task1 done
|
|
5597
|
+
* // task2 interrupted
|
|
5598
|
+
* // more work...
|
|
5599
|
+
* // { _id: 'Exit', _tag: 'Success', value: 'task1' }
|
|
5600
|
+
* ```
|
|
5601
|
+
*
|
|
5602
|
+
* @example
|
|
5603
|
+
* ```ts
|
|
5604
|
+
* // Title: One Task Fails, One Succeeds
|
|
5605
|
+
* import { Effect, Console } from "effect"
|
|
5606
|
+
*
|
|
5607
|
+
* const task1 = Effect.fail("task1").pipe(
|
|
5608
|
+
* Effect.delay("100 millis"),
|
|
5609
|
+
* Effect.tap(Console.log("task1 done")),
|
|
5610
|
+
* Effect.onInterrupt(() =>
|
|
5611
|
+
* Console.log("task1 interrupted").pipe(Effect.delay("100 millis"))
|
|
5612
|
+
* )
|
|
5613
|
+
* )
|
|
5614
|
+
* const task2 = Effect.succeed("task2").pipe(
|
|
5615
|
+
* Effect.delay("200 millis"),
|
|
5616
|
+
* Effect.tap(Console.log("task2 done")),
|
|
5617
|
+
* Effect.onInterrupt(() =>
|
|
5618
|
+
* Console.log("task2 interrupted").pipe(Effect.delay("100 millis"))
|
|
5619
|
+
* )
|
|
4330
5620
|
* )
|
|
4331
5621
|
*
|
|
4332
|
-
* Effect.
|
|
4333
|
-
*
|
|
5622
|
+
* const program = Effect.raceFirst(task1, task2).pipe(
|
|
5623
|
+
* Effect.tap(Console.log("more work..."))
|
|
5624
|
+
* )
|
|
5625
|
+
*
|
|
5626
|
+
* Effect.runPromiseExit(program).then(console.log)
|
|
5627
|
+
* // Output:
|
|
5628
|
+
* // task2 interrupted
|
|
5629
|
+
* // {
|
|
5630
|
+
* // _id: 'Exit',
|
|
5631
|
+
* // _tag: 'Failure',
|
|
5632
|
+
* // cause: { _id: 'Cause', _tag: 'Fail', failure: 'task1' }
|
|
5633
|
+
* // }
|
|
4334
5634
|
* ```
|
|
4335
5635
|
*
|
|
4336
|
-
* @
|
|
4337
|
-
*
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
/**
|
|
4341
|
-
* @since 2.0.0
|
|
4342
|
-
* @category sequencing
|
|
4343
|
-
*/
|
|
4344
|
-
export const flatten = core.flatten;
|
|
4345
|
-
/**
|
|
4346
|
-
* Returns an effect that races this effect with all the specified effects,
|
|
4347
|
-
* yielding the value of the first effect to succeed with a value. Losers of
|
|
4348
|
-
* the race will be interrupted immediately
|
|
5636
|
+
* @example
|
|
5637
|
+
* ```ts
|
|
5638
|
+
* // Title: Using Effect.disconnect for Quicker Return
|
|
5639
|
+
* import { Effect, Console } from "effect"
|
|
4349
5640
|
*
|
|
4350
|
-
*
|
|
4351
|
-
*
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
*
|
|
4356
|
-
*
|
|
4357
|
-
*
|
|
4358
|
-
*
|
|
5641
|
+
* const task1 = Effect.succeed("task1").pipe(
|
|
5642
|
+
* Effect.delay("100 millis"),
|
|
5643
|
+
* Effect.tap(Console.log("task1 done")),
|
|
5644
|
+
* Effect.onInterrupt(() =>
|
|
5645
|
+
* Console.log("task1 interrupted").pipe(Effect.delay("100 millis"))
|
|
5646
|
+
* )
|
|
5647
|
+
* )
|
|
5648
|
+
* const task2 = Effect.succeed("task2").pipe(
|
|
5649
|
+
* Effect.delay("200 millis"),
|
|
5650
|
+
* Effect.tap(Console.log("task2 done")),
|
|
5651
|
+
* Effect.onInterrupt(() =>
|
|
5652
|
+
* Console.log("task2 interrupted").pipe(Effect.delay("100 millis"))
|
|
5653
|
+
* )
|
|
5654
|
+
* )
|
|
4359
5655
|
*
|
|
4360
|
-
*
|
|
4361
|
-
*
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
* Returns an effect that races this effect with the specified effect,
|
|
4366
|
-
* yielding the first result to complete, whether by success or failure. If
|
|
4367
|
-
* neither effect completes, then the composed effect will not complete.
|
|
5656
|
+
* // Race the two tasks with disconnect to allow quicker return
|
|
5657
|
+
* const program = Effect.raceFirst(
|
|
5658
|
+
* Effect.disconnect(task1),
|
|
5659
|
+
* Effect.disconnect(task2)
|
|
5660
|
+
* ).pipe(Effect.tap(Console.log("more work...")))
|
|
4368
5661
|
*
|
|
4369
|
-
*
|
|
4370
|
-
*
|
|
4371
|
-
*
|
|
4372
|
-
*
|
|
4373
|
-
*
|
|
4374
|
-
*
|
|
5662
|
+
* Effect.runPromiseExit(program).then(console.log)
|
|
5663
|
+
* // Output:
|
|
5664
|
+
* // task1 done
|
|
5665
|
+
* // more work...
|
|
5666
|
+
* // { _id: 'Exit', _tag: 'Success', value: 'task1' }
|
|
5667
|
+
* // task2 interrupted
|
|
5668
|
+
* ```
|
|
4375
5669
|
*
|
|
4376
5670
|
* @since 2.0.0
|
|
4377
|
-
* @category
|
|
5671
|
+
* @category Racing
|
|
4378
5672
|
*/
|
|
4379
5673
|
export const raceFirst = circular.raceFirst;
|
|
4380
5674
|
/**
|
|
4381
|
-
*
|
|
4382
|
-
*
|
|
5675
|
+
* Races two effects and calls a finisher when the first one completes.
|
|
5676
|
+
*
|
|
5677
|
+
* **Details**
|
|
5678
|
+
*
|
|
5679
|
+
* This function runs two effects concurrently and calls a specified “finisher”
|
|
5680
|
+
* function once one of the effects completes, regardless of whether it succeeds
|
|
5681
|
+
* or fails.
|
|
5682
|
+
*
|
|
5683
|
+
* The finisher functions for each effect allow you to handle the results of
|
|
5684
|
+
* each effect as soon as they complete.
|
|
5685
|
+
*
|
|
5686
|
+
* The function takes two finisher callbacks, one for each effect, and allows
|
|
5687
|
+
* you to specify how to handle the result of the race.
|
|
5688
|
+
*
|
|
5689
|
+
* **When to Use**
|
|
5690
|
+
*
|
|
5691
|
+
* This function is useful when you need to react to the completion of either
|
|
5692
|
+
* effect without waiting for both to finish. It can be used whenever you want
|
|
5693
|
+
* to take action based on the first available result.
|
|
5694
|
+
*
|
|
5695
|
+
* @example
|
|
5696
|
+
* ```ts
|
|
5697
|
+
* // Title: Handling Results of Concurrent Tasks
|
|
5698
|
+
* import { Effect, Console } from "effect"
|
|
5699
|
+
*
|
|
5700
|
+
* const task1 = Effect.succeed("task1").pipe(
|
|
5701
|
+
* Effect.delay("100 millis"),
|
|
5702
|
+
* Effect.tap(Console.log("task1 done")),
|
|
5703
|
+
* Effect.onInterrupt(() =>
|
|
5704
|
+
* Console.log("task1 interrupted").pipe(Effect.delay("100 millis"))
|
|
5705
|
+
* )
|
|
5706
|
+
* )
|
|
5707
|
+
* const task2 = Effect.succeed("task2").pipe(
|
|
5708
|
+
* Effect.delay("200 millis"),
|
|
5709
|
+
* Effect.tap(Console.log("task2 done")),
|
|
5710
|
+
* Effect.onInterrupt(() =>
|
|
5711
|
+
* Console.log("task2 interrupted").pipe(Effect.delay("100 millis"))
|
|
5712
|
+
* )
|
|
5713
|
+
* )
|
|
5714
|
+
*
|
|
5715
|
+
* const program = Effect.raceWith(task1, task2, {
|
|
5716
|
+
* onSelfDone: (exit) => Console.log(`task1 exited with ${exit}`),
|
|
5717
|
+
* onOtherDone: (exit) => Console.log(`task2 exited with ${exit}`)
|
|
5718
|
+
* })
|
|
5719
|
+
*
|
|
5720
|
+
* Effect.runFork(program)
|
|
5721
|
+
* // Output:
|
|
5722
|
+
* // task1 done
|
|
5723
|
+
* // task1 exited with {
|
|
5724
|
+
* // "_id": "Exit",
|
|
5725
|
+
* // "_tag": "Success",
|
|
5726
|
+
* // "value": "task1"
|
|
5727
|
+
* // }
|
|
5728
|
+
* // task2 interrupted
|
|
5729
|
+
* ```
|
|
4383
5730
|
*
|
|
4384
5731
|
* @since 2.0.0
|
|
4385
|
-
* @category
|
|
5732
|
+
* @category Racing
|
|
4386
5733
|
*/
|
|
4387
5734
|
export const raceWith = fiberRuntime.raceWith;
|
|
4388
5735
|
/**
|
|
@@ -4992,16 +6339,23 @@ export const isSuccess = effect.isSuccess;
|
|
|
4992
6339
|
* Handles both success and failure cases of an effect without performing side
|
|
4993
6340
|
* effects.
|
|
4994
6341
|
*
|
|
6342
|
+
* **Details**
|
|
6343
|
+
*
|
|
4995
6344
|
* `match` lets you define custom handlers for both success and failure
|
|
4996
6345
|
* scenarios. You provide separate functions to handle each case, allowing you
|
|
4997
6346
|
* to process the result if the effect succeeds, or handle the error if the
|
|
4998
|
-
* effect fails.
|
|
4999
|
-
*
|
|
6347
|
+
* effect fails.
|
|
6348
|
+
*
|
|
6349
|
+
* **When to Use**
|
|
6350
|
+
*
|
|
6351
|
+
* This is useful for structuring your code to respond differently to success or
|
|
6352
|
+
* failure without triggering side effects.
|
|
5000
6353
|
*
|
|
5001
6354
|
* @see {@link matchEffect} if you need to perform side effects in the handlers.
|
|
5002
6355
|
*
|
|
5003
6356
|
* @example
|
|
5004
6357
|
* ```ts
|
|
6358
|
+
* // Title: Handling Both Success and Failure Cases
|
|
5005
6359
|
* import { Effect } from "effect"
|
|
5006
6360
|
*
|
|
5007
6361
|
* const success: Effect.Effect<number, Error> = Effect.succeed(42)
|
|
@@ -5036,15 +6390,54 @@ export const match = effect.match;
|
|
|
5036
6390
|
/**
|
|
5037
6391
|
* Handles failures by matching the cause of failure.
|
|
5038
6392
|
*
|
|
5039
|
-
*
|
|
5040
|
-
*
|
|
5041
|
-
*
|
|
5042
|
-
*
|
|
5043
|
-
*
|
|
6393
|
+
* **Details**
|
|
6394
|
+
*
|
|
6395
|
+
* The `matchCause` function allows you to handle failures with access to the
|
|
6396
|
+
* full cause of the failure within a fiber.
|
|
6397
|
+
*
|
|
6398
|
+
* **When to Use**
|
|
6399
|
+
*
|
|
6400
|
+
* This is useful for differentiating between different types of errors, such as
|
|
6401
|
+
* regular failures, defects, or interruptions. You can provide specific
|
|
6402
|
+
* handling logic for each failure type based on the cause.
|
|
5044
6403
|
*
|
|
5045
|
-
* @see {@link matchCauseEffect} if you need to perform side effects in the
|
|
6404
|
+
* @see {@link matchCauseEffect} if you need to perform side effects in the
|
|
6405
|
+
* handlers.
|
|
5046
6406
|
* @see {@link match} if you don't need to handle the cause of the failure.
|
|
5047
6407
|
*
|
|
6408
|
+
* @example
|
|
6409
|
+
* ```ts
|
|
6410
|
+
* // Title: Handling Different Failure Causes
|
|
6411
|
+
* import { Effect } from "effect"
|
|
6412
|
+
*
|
|
6413
|
+
* const task: Effect.Effect<number, Error> = Effect.die("Uh oh!")
|
|
6414
|
+
*
|
|
6415
|
+
* const program = Effect.matchCause(task, {
|
|
6416
|
+
* onFailure: (cause) => {
|
|
6417
|
+
* switch (cause._tag) {
|
|
6418
|
+
* case "Fail":
|
|
6419
|
+
* // Handle standard failure
|
|
6420
|
+
* return `Fail: ${cause.error.message}`
|
|
6421
|
+
* case "Die":
|
|
6422
|
+
* // Handle defects (unexpected errors)
|
|
6423
|
+
* return `Die: ${cause.defect}`
|
|
6424
|
+
* case "Interrupt":
|
|
6425
|
+
* // Handle interruption
|
|
6426
|
+
* return `${cause.fiberId} interrupted!`
|
|
6427
|
+
* }
|
|
6428
|
+
* // Fallback for other causes
|
|
6429
|
+
* return "failed due to other causes"
|
|
6430
|
+
* },
|
|
6431
|
+
* onSuccess: (value) =>
|
|
6432
|
+
* // task completes successfully
|
|
6433
|
+
* `succeeded with ${value} value`
|
|
6434
|
+
* })
|
|
6435
|
+
*
|
|
6436
|
+
* Effect.runPromise(program).then(console.log)
|
|
6437
|
+
* // Output: "Die: Uh oh!"
|
|
6438
|
+
*
|
|
6439
|
+
* ```
|
|
6440
|
+
*
|
|
5048
6441
|
* @since 2.0.0
|
|
5049
6442
|
* @category getters & folding
|
|
5050
6443
|
*/
|
|
@@ -5052,18 +6445,21 @@ export const matchCause = core.matchCause;
|
|
|
5052
6445
|
/**
|
|
5053
6446
|
* Handles failures with access to the cause and allows performing side effects.
|
|
5054
6447
|
*
|
|
5055
|
-
*
|
|
5056
|
-
*
|
|
5057
|
-
*
|
|
5058
|
-
*
|
|
5059
|
-
*
|
|
5060
|
-
*
|
|
6448
|
+
* **Details**
|
|
6449
|
+
*
|
|
6450
|
+
* The `matchCauseEffect` function works similarly to {@link matchCause}, but it
|
|
6451
|
+
* also allows you to perform additional side effects based on the failure
|
|
6452
|
+
* cause. This function provides access to the complete cause of the failure,
|
|
6453
|
+
* making it possible to differentiate between various failure types, and allows
|
|
6454
|
+
* you to respond accordingly while performing side effects (like logging or
|
|
6455
|
+
* other operations).
|
|
5061
6456
|
*
|
|
5062
6457
|
* @see {@link matchCause} if you don't need side effects and only want to handle the result or failure.
|
|
5063
6458
|
* @see {@link matchEffect} if you don't need to handle the cause of the failure.
|
|
5064
6459
|
*
|
|
5065
6460
|
* @example
|
|
5066
6461
|
* ```ts
|
|
6462
|
+
* // Title: Handling Different Failure Causes with Side Effects
|
|
5067
6463
|
* import { Effect, Console } from "effect"
|
|
5068
6464
|
*
|
|
5069
6465
|
* const task: Effect.Effect<number, Error> = Effect.die("Uh oh!")
|
|
@@ -5089,7 +6485,7 @@ export const matchCause = core.matchCause;
|
|
|
5089
6485
|
* Console.log(`succeeded with ${value} value`)
|
|
5090
6486
|
* })
|
|
5091
6487
|
*
|
|
5092
|
-
* Effect.
|
|
6488
|
+
* Effect.runPromise(program)
|
|
5093
6489
|
* // Output: "Die: Uh oh!"
|
|
5094
6490
|
* ```
|
|
5095
6491
|
*
|
|
@@ -5101,13 +6497,57 @@ export const matchCauseEffect = core.matchCauseEffect;
|
|
|
5101
6497
|
* Handles both success and failure cases of an effect, allowing for additional
|
|
5102
6498
|
* side effects.
|
|
5103
6499
|
*
|
|
5104
|
-
*
|
|
5105
|
-
*
|
|
5106
|
-
*
|
|
5107
|
-
*
|
|
5108
|
-
*
|
|
6500
|
+
* **Details**
|
|
6501
|
+
*
|
|
6502
|
+
* The `matchEffect` function is similar to {@link match}, but it enables you to
|
|
6503
|
+
* perform side effects in the handlers for both success and failure outcomes.
|
|
6504
|
+
*
|
|
6505
|
+
* **When to Use**
|
|
6506
|
+
*
|
|
6507
|
+
* This is useful when you need to execute additional actions, like logging or
|
|
6508
|
+
* notifying users, based on whether an effect succeeds or fails.
|
|
6509
|
+
*
|
|
6510
|
+
* @see {@link match} if you don't need side effects and only want to handle the
|
|
6511
|
+
* result or failure.
|
|
6512
|
+
*
|
|
6513
|
+
* @example
|
|
6514
|
+
* ```ts
|
|
6515
|
+
* // Title: Handling Both Success and Failure Cases with Side Effects
|
|
6516
|
+
* import { Effect } from "effect"
|
|
6517
|
+
*
|
|
6518
|
+
* const success: Effect.Effect<number, Error> = Effect.succeed(42)
|
|
6519
|
+
* const failure: Effect.Effect<number, Error> = Effect.fail(
|
|
6520
|
+
* new Error("Uh oh!")
|
|
6521
|
+
* )
|
|
6522
|
+
*
|
|
6523
|
+
* const program1 = Effect.matchEffect(success, {
|
|
6524
|
+
* onFailure: (error) =>
|
|
6525
|
+
* Effect.succeed(`failure: ${error.message}`).pipe(
|
|
6526
|
+
* Effect.tap(Effect.log)
|
|
6527
|
+
* ),
|
|
6528
|
+
* onSuccess: (value) =>
|
|
6529
|
+
* Effect.succeed(`success: ${value}`).pipe(Effect.tap(Effect.log))
|
|
6530
|
+
* })
|
|
6531
|
+
*
|
|
6532
|
+
* console.log(Effect.runSync(program1))
|
|
6533
|
+
* // Output:
|
|
6534
|
+
* // timestamp=... level=INFO fiber=#0 message="success: 42"
|
|
6535
|
+
* // success: 42
|
|
6536
|
+
*
|
|
6537
|
+
* const program2 = Effect.matchEffect(failure, {
|
|
6538
|
+
* onFailure: (error) =>
|
|
6539
|
+
* Effect.succeed(`failure: ${error.message}`).pipe(
|
|
6540
|
+
* Effect.tap(Effect.log)
|
|
6541
|
+
* ),
|
|
6542
|
+
* onSuccess: (value) =>
|
|
6543
|
+
* Effect.succeed(`success: ${value}`).pipe(Effect.tap(Effect.log))
|
|
6544
|
+
* })
|
|
5109
6545
|
*
|
|
5110
|
-
*
|
|
6546
|
+
* console.log(Effect.runSync(program2))
|
|
6547
|
+
* // Output:
|
|
6548
|
+
* // timestamp=... level=INFO fiber=#1 message="failure: Uh oh!"
|
|
6549
|
+
* // failure: Uh oh!
|
|
6550
|
+
* ```
|
|
5111
6551
|
*
|
|
5112
6552
|
* @since 2.0.0
|
|
5113
6553
|
* @category getters & folding
|