@@ -256,6 +256,30 @@ export class FIO<E1 = unknown, A1 = unknown, R1 = NoEnv> {
256
256
return fio . chain ( Id )
257
257
}
258
258
259
+ /**
260
+ * Takes in a effect-ful function that return a FIO and unwraps it.
261
+ * This is an alias to `FIO.flatten(UIO(fn))`
262
+ *
263
+ * ```ts
264
+ * // An impure function that creates mutable state but also returns a FIO.
265
+ * const FN = () => {
266
+ * let count = 0
267
+ *
268
+ * return FIO.try(() => count++)
269
+ * }
270
+ * // Using flatten
271
+ * FIO.flatten(UIO(FN))
272
+ *
273
+ * // Using flattenM
274
+ * FIO.flattenM(FN)
275
+ * ```
276
+ */
277
+ public static flattenM < E1 , A1 , R1 > (
278
+ fio : ( ) => FIO < E1 , A1 , R1 >
279
+ ) : FIO < E1 , A1 , R1 > {
280
+ return FIO . flatten ( UIO ( fio ) )
281
+ }
282
+
259
283
/**
260
284
* Creates a new [[Fiber]] to run the given [[IO]].
261
285
*/
@@ -668,49 +692,69 @@ export class FIO<E1 = unknown, A1 = unknown, R1 = NoEnv> {
668
692
c : ( e1 : A1 , e2 : A2 ) => C
669
693
) : FIO < E1 | E2 , C , R1 & R2 > {
670
694
// Create Caches
671
- const cache = ExitRef < E1 , A1 > ( ) . zip ( ExitRef < E2 , A2 > ( ) )
672
-
673
- // Create a Counter and an Await
674
- return Ref . of ( 0 )
675
- . zip ( Await . of < never , boolean > ( ) )
676
- . chain ( ( { 0 : count , 1 : done } ) => {
677
- // Cancels the provided fiber on exit status.
678
- // tslint:disable-next-line:no-shadowed-variable
679
- const coordinate = < E1 , A1 , E2 , A2 > (
680
- exit : Either < E1 , A1 > ,
681
- fiber : Fiber < E2 , A2 > ,
682
- ref : Ref < Either < E1 , A1 > >
683
- ) : UIO < boolean > =>
684
- ref
685
- . set ( exit )
686
- . chain ( e =>
687
- e . fold (
688
- FIO . of ( false ) ,
689
- ( ) => fiber . abort . and ( done . set ( FIO . of ( true ) ) ) ,
690
- ( ) =>
691
- count
692
- . update ( _ => _ + 1 )
693
- . and (
694
- count . read . chain ( value =>
695
- value === 2 ? done . set ( FIO . of ( true ) ) : FIO . of ( false )
696
- )
697
- )
695
+ const Caches = ExitRef < E1 , A1 > ( ) . zip ( ExitRef < E2 , A2 > ( ) )
696
+
697
+ // Maintains the count of results produced
698
+ const Counter = Ref . of ( 0 )
699
+
700
+ // Is set only when the IO is completed.
701
+ const Done = Await . of < never , boolean > ( )
702
+
703
+ return Counter . zip ( Done ) . chain ( ( { 0 : count , 1 : isDone } ) => {
704
+ // Cancels the provided fiber on exit status.
705
+ const coordinate = < EE1 , AA1 , EE2 , AA2 > (
706
+ exit : Either < EE1 , AA1 > ,
707
+ fiber : Fiber < EE2 , AA2 > ,
708
+ cache : Ref < Either < EE1 , AA1 > >
709
+ ) : UIO < boolean > => {
710
+ // Saves the result into a [[Ref]] instance
711
+ const cacheResult = cache . set ( exit )
712
+
713
+ // Abort the other Fiber
714
+ const abortFiber = fiber . abort
715
+
716
+ // Set the result
717
+ const markAsDone = isDone . set ( FIO . of ( true ) )
718
+
719
+ // Increases the result count by 1
720
+ const incCount = count . update ( _ => _ + 1 )
721
+
722
+ return cacheResult . and (
723
+ exit . fold (
724
+ FIO . of ( false ) ,
725
+
726
+ // On failure —
727
+ // 1. Increase count
728
+ // 2. Abort fiber
729
+ // 3. Set final result
730
+ ( ) => abortFiber . and ( markAsDone ) ,
731
+
732
+ // On success —
733
+ // 1. Increase count
734
+ // 2. if count === 2 : Set final result
735
+ ( ) =>
736
+ incCount . and (
737
+ count . read . chain ( value =>
738
+ value === 2 ? markAsDone : FIO . of ( false )
739
+ )
698
740
)
699
- )
700
-
701
- return cache . chain ( ( { 0 : c1 , 1 : c2 } ) =>
702
- this . raceWith (
703
- that ,
704
- ( exit , fiber ) => coordinate ( exit , fiber , c1 ) . void ,
705
- ( exit , fiber ) => coordinate ( exit , fiber , c2 ) . void
706
741
)
707
- . and ( done . get )
708
- . and (
709
- c1 . read
710
- . chain ( FIO . fromEither )
711
- . zipWith ( c2 . read . chain ( FIO . fromEither ) , c )
712
- )
713
742
)
714
- } )
743
+ }
744
+
745
+ return Caches . chain ( ( { 0 : cacheL , 1 : cacheR } ) =>
746
+ this . raceWith (
747
+ that ,
748
+ ( exit , fiber ) => coordinate ( exit , fiber , cacheL ) . void ,
749
+ ( exit , fiber ) => coordinate ( exit , fiber , cacheR ) . void
750
+ )
751
+ . and ( isDone . get )
752
+ . and (
753
+ cacheL . read
754
+ . chain ( FIO . fromEither )
755
+ . zipWith ( cacheR . read . chain ( FIO . fromEither ) , c )
756
+ )
757
+ )
758
+ } )
715
759
}
716
760
}
0 commit comments