Skip to content

Commit cc817ee

Browse files
committed
feat(fio): add flattenM static method
1 parent 0b325aa commit cc817ee

File tree

1 file changed

+85
-41
lines changed

1 file changed

+85
-41
lines changed

src/main/FIO.ts

Lines changed: 85 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,30 @@ export class FIO<E1 = unknown, A1 = unknown, R1 = NoEnv> {
256256
return fio.chain(Id)
257257
}
258258

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+
259283
/**
260284
* Creates a new [[Fiber]] to run the given [[IO]].
261285
*/
@@ -668,49 +692,69 @@ export class FIO<E1 = unknown, A1 = unknown, R1 = NoEnv> {
668692
c: (e1: A1, e2: A2) => C
669693
): FIO<E1 | E2, C, R1 & R2> {
670694
// 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+
)
698740
)
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
706741
)
707-
.and(done.get)
708-
.and(
709-
c1.read
710-
.chain(FIO.fromEither)
711-
.zipWith(c2.read.chain(FIO.fromEither), c)
712-
)
713742
)
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+
})
715759
}
716760
}

0 commit comments

Comments
 (0)