Either; otherwise, apply the unwrapped left value to leftFn and return the resulting
- * Either.
- *
- * @param leftFn the function to apply if a left value
- * @param rightFn the function to apply if a right value
- * @param A, if this {@link IO} successfully
+ * yields a result, return it; otherwise, map the {@link Throwable} to the result type and return that.
+ *
+ * @param recoveryFn the recovery function
+ * @return the guarded {@link IO}
+ */
+ default IO exceptionally(Function super Throwable, ? extends A> recoveryFn) {
+ return new IO() {
+ @Override
+ public A unsafePerformIO() {
+ return Try.trying(IO.this::unsafePerformIO).recover(recoveryFn);
+ }
+
+ @Override
+ public CompletableFuture unsafePerformAsyncIO() {
+ return IO.this.unsafePerformAsyncIO().exceptionally(recoveryFn::apply);
+ }
+
+ @Override
+ public CompletableFuture unsafePerformAsyncIO(Executor executor) {
+ return IO.this.unsafePerformAsyncIO(executor).exceptionally(recoveryFn::apply);
+ }
+ };
+ }
+
/**
* {@inheritDoc}
*/
@Override
default IO flatMap(Function super A, ? extends Monad>> f) {
- return () -> f.apply(unsafePerformIO()).
+ * Note that constructing an {@link IO} this way results in no intermediate futures being constructed by either
+ * {@link IO#unsafePerformAsyncIO()} or {@link IO#unsafePerformAsyncIO(Executor)}, and {@link IO#unsafePerformIO()}
+ * is synonymous with invoking {@link CompletableFuture#get()} on the externally managed future.
+ *
+ * @param supplier the source of externally managed {@link CompletableFuture completable futures}
+ * @param the result type
+ * @return the {@link IO}
+ */
+ static IO externallyManaged(SupplierM. Useful for composition to avoid
+ * mutating a map reference.
+ *
+ * @param