com.github.tonivade.purefun.instances.FutureInstances Maven / Gradle / Ivy
/*
* Copyright (c) 2018-2020, Antonio Gabriel Muñoz Conejo
* Distributed under the terms of the MIT License
*/
package com.github.tonivade.purefun.instances;
import static com.github.tonivade.purefun.Function1.identity;
import static com.github.tonivade.purefun.Precondition.checkNonNull;
import static com.github.tonivade.purefun.concurrent.FutureOf.toFuture;
import java.time.Duration;
import java.util.concurrent.Executor;
import com.github.tonivade.purefun.Consumer1;
import com.github.tonivade.purefun.Function1;
import com.github.tonivade.purefun.Kind;
import com.github.tonivade.purefun.Producer;
import com.github.tonivade.purefun.Tuple;
import com.github.tonivade.purefun.Tuple2;
import com.github.tonivade.purefun.Unit;
import com.github.tonivade.purefun.concurrent.Future;
import com.github.tonivade.purefun.concurrent.FutureOf;
import com.github.tonivade.purefun.concurrent.Future_;
import com.github.tonivade.purefun.concurrent.Promise;
import com.github.tonivade.purefun.type.Either;
import com.github.tonivade.purefun.type.Try;
import com.github.tonivade.purefun.typeclasses.Applicative;
import com.github.tonivade.purefun.typeclasses.Async;
import com.github.tonivade.purefun.typeclasses.Bracket;
import com.github.tonivade.purefun.typeclasses.Concurrent;
import com.github.tonivade.purefun.typeclasses.Defer;
import com.github.tonivade.purefun.typeclasses.Fiber;
import com.github.tonivade.purefun.typeclasses.Functor;
import com.github.tonivade.purefun.typeclasses.Monad;
import com.github.tonivade.purefun.typeclasses.MonadDefer;
import com.github.tonivade.purefun.typeclasses.MonadError;
import com.github.tonivade.purefun.typeclasses.MonadThrow;
public interface FutureInstances {
static Functor functor() {
return FutureFunctor.INSTANCE;
}
static Applicative applicative() {
return applicative(Future.DEFAULT_EXECUTOR);
}
static Applicative applicative(Executor executor) {
return FutureApplicative.instance(checkNonNull(executor));
}
static Monad monad() {
return monad(Future.DEFAULT_EXECUTOR);
}
static Monad monad(Executor executor) {
return FutureMonad.instance(checkNonNull(executor));
}
static MonadError monadError() {
return monadError(Future.DEFAULT_EXECUTOR);
}
static MonadError monadError(Executor executor) {
return FutureMonadThrow.instance(checkNonNull(executor));
}
static MonadDefer monadDefer() {
return monadDefer(Future.DEFAULT_EXECUTOR);
}
static MonadDefer monadDefer(Executor executor) {
return FutureMonadDefer.instance(checkNonNull(executor));
}
static Async async() {
return async(Future.DEFAULT_EXECUTOR);
}
static Async async(Executor executor) {
return FutureAsync.instance(checkNonNull(executor));
}
static Concurrent concurrent() {
return concurrent(Future.DEFAULT_EXECUTOR);
}
static Concurrent concurrent(Executor executor) {
return FutureConcurrent.instance(checkNonNull(executor));
}
}
interface FutureFunctor extends Functor {
FutureFunctor INSTANCE = new FutureFunctor() {};
@Override
default Kind map(Kind value, Function1 super T, ? extends R> mapper) {
return value.fix(toFuture()).map(mapper);
}
}
interface ExecutorHolder {
Executor executor();
}
interface FuturePure extends Applicative, ExecutorHolder {
@Override
default Kind pure(T value) {
return Future.success(executor(), value);
}
}
interface FutureApplicative extends FuturePure {
static FutureApplicative instance(Executor executor) {
return () -> executor;
}
@Override
default Kind ap(Kind value,
Kind> apply) {
return value.fix(FutureOf::narrowK).ap(apply.fix(FutureOf::narrowK));
}
}
interface FutureMonad extends FuturePure, Monad {
static FutureMonad instance(Executor executor) {
return () -> executor;
}
@Override
default Kind flatMap(Kind value,
Function1 super T, ? extends Kind> map) {
return value.fix(toFuture()).flatMap(map.andThen(FutureOf::narrowK));
}
/**
* XXX In order to create real parallel computations, we need to override ap to use the
* applicative version of the ap method
*/
@Override
default Kind ap(Kind value,
Kind> apply) {
return FutureInstances.applicative().ap(value, apply);
}
}
interface FutureMonadThrow extends FutureMonad, MonadThrow {
static FutureMonadThrow instance(Executor executor) {
return () -> executor;
}
@Override
default Kind raiseError(Throwable error) {
return Future.failure(executor(), error);
}
@Override
default Kind handleErrorWith(
Kind value,
Function1 super Throwable, ? extends Kind> handler) {
return value.fix(toFuture()).fold(handler.andThen(FutureOf::narrowK),
success -> Future.success(executor(), success)).flatMap(identity());
}
}
interface FutureDefer extends Defer, ExecutorHolder {
@Override
default Kind defer(Producer extends Kind> defer) {
return Future.defer(executor(), defer.map(FutureOf::narrowK)::get);
}
}
interface FutureBracket extends Bracket, ExecutorHolder {
@Override
default Kind bracket(Kind acquire,
Function1 super A, ? extends Kind> use, Consumer1 super A> release) {
return Future.bracket(executor(), acquire.fix(toFuture()), use.andThen(FutureOf::narrowK), release);
}
}
interface FutureMonadDefer extends MonadDefer, FutureMonadThrow, FutureDefer, FutureBracket {
static FutureMonadDefer instance(Executor executor) {
return () -> executor;
}
@Override
default Kind sleep(Duration duration) {
return Future.sleep(executor(), duration);
}
}
interface FutureAsync extends Async, FutureMonadDefer {
static FutureAsync instance(Executor executor) {
return () -> executor;
}
@Override
default Kind asyncF(
Function1>, Kind> consumer) {
return Future.asyncF(executor(), consumer.andThen(FutureOf::narrowK));
}
}
interface FutureConcurrent extends Concurrent, FutureAsync {
static FutureConcurrent instance(Executor executor) {
return () -> executor;
}
@Override
default Future> fork(Kind value) {
return Future.later(executor(), () -> fiber(executor(), value.fix(toFuture())));
}
@Override
default Future>, Tuple2, B>>> racePair(
Kind fa, Kind fb) {
Kind>, Tuple2, B>>> async =
async(consumer -> {
Fiber fiberA = fiber(executor(), fa);
Fiber fiberB = fiber(executor(), fb);
Promise>, Tuple2, B>>> promise = Promise.make();
promise.onComplete(consumer);
fa.fix(toFuture()).onSuccess(a -> promise.tryComplete(Try.success(Either.left(Tuple.of(a, fiberB)))));
fb.fix(toFuture()).onSuccess(b -> promise.tryComplete(Try.success(Either.right(Tuple.of(fiberA, b)))));
fa.fix(toFuture()).onFailure(
error1 -> fb.fix(toFuture()).onFailure(
error2 -> promise.tryComplete(Try.failure("failed: " + error1 + " " + error2))));
});
return async.fix(toFuture());
}
static Fiber fiber(Executor executor, Kind future) {
return Fiber.of(() -> future, () -> Future.exec(executor, () -> future.fix(toFuture()).cancel(true)));
}
} © 2015 - 2025 Weber Informatics LLC | Privacy Policy