All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.tonivade.purefun.instances.PureIOInstances Maven / Gradle / Ivy

/*
 * Copyright (c) 2018-2022, 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.effect.PureIOOf.toPureIO;
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.Tuple2;
import com.github.tonivade.purefun.Unit;
import com.github.tonivade.purefun.concurrent.Future;
import com.github.tonivade.purefun.data.Sequence;
import com.github.tonivade.purefun.effect.UIO;
import com.github.tonivade.purefun.effect.PureIO;
import com.github.tonivade.purefun.effect.PureIOOf;
import com.github.tonivade.purefun.effect.PureIO_;
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.Console;
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;
import com.github.tonivade.purefun.typeclasses.Runtime;

@SuppressWarnings("unchecked")
public interface PureIOInstances {

  static  Functor, E>> functor() {
    return PureIOFunctor.INSTANCE;
  }

  static  Applicative, E>> applicative() {
    return PureIOApplicative.INSTANCE;
  }

  static  Monad, E>> monad() {
    return PureIOMonad.INSTANCE;
  }

  static  MonadError, E>, E> monadError() {
    return PureIOMonadError.INSTANCE;
  }

  static  MonadThrow, Throwable>> monadThrow() {
    return PureIOMonadThrow.INSTANCE;
  }

  static  MonadDefer, Throwable>> monadDefer() {
    return PureIOMonadDefer.INSTANCE;
  }

  static  Async, Throwable>> async() {
    return PureIOAsync.INSTANCE;
  }

  static  Concurrent, Throwable>> concurrent() {
    return concurrent(Future.DEFAULT_EXECUTOR);
  }

  static  Concurrent, Throwable>> concurrent(Executor executor) {
    return PureIOConcurrent.instance(executor);
  }

  static  Console, Throwable>> console() {
    return PureIOConsole.INSTANCE;
  }
  
  static  Runtime, E>> runtime(R env) {
    return PureIORuntime.instance(env);
  }
}

interface PureIOFunctor extends Functor, E>> {

  @SuppressWarnings("rawtypes")
  PureIOFunctor INSTANCE = new PureIOFunctor() {};

  @Override
  default  PureIO map(
      Kind, E>, ? extends A> value, 
      Function1 map) {
    return PureIOOf.narrowK(value).map(map);
  }
}

interface PureIOPure extends Applicative, E>> {

  @Override
  default  PureIO pure(A value) {
    return PureIO.pure(value);
  }
}

interface PureIOApplicative extends PureIOPure {

  @SuppressWarnings("rawtypes")
  PureIOApplicative INSTANCE = new PureIOApplicative() {};

  @Override
  default  PureIO
          ap(Kind, E>, ? extends A> value,
             Kind, E>, ? extends Function1> apply) {
    return value.fix(PureIOOf::narrowK).ap(apply.fix(PureIOOf::narrowK));
  }
}

interface PureIOMonad extends PureIOPure, Monad, E>> {

  @SuppressWarnings("rawtypes")
  PureIOMonad INSTANCE = new PureIOMonad() {};

  @Override
  default  PureIO
          flatMap(Kind, E>, ? extends A> value,
                  Function1, E>, ? extends B>> map) {
    return value.fix(toPureIO()).flatMap(map.andThen(PureIOOf::narrowK));
  }
}

interface PureIOMonadError extends PureIOMonad, MonadError, E>, E> {

  @SuppressWarnings("rawtypes")
  PureIOMonadError INSTANCE = new PureIOMonadError() {};

  @Override
  default  PureIO raiseError(E error) {
    return PureIO.raiseError(error);
  }

  @Override
  default  PureIO handleErrorWith(
      Kind, E>, A> value,
      Function1, E>, ? extends A>> handler) {
    // XXX: java8 fails to infer types, I have to do this in steps
    Function1> mapError = handler.andThen(PureIOOf::narrowK);
    Function1> map = PureIO::pure;
    PureIO PureIO = PureIOOf.narrowK(value);
    return PureIO.foldM(mapError, map);
  }
}

interface PureIOMonadThrow
    extends PureIOMonadError, MonadThrow, Throwable>> {
  @SuppressWarnings("rawtypes")
  PureIOMonadThrow INSTANCE = new PureIOMonadThrow() {};
}

interface PureIODefer extends Defer, E>> {

  @Override
  default  PureIO
          defer(Producer, E>, ? extends A>> defer) {
    return PureIO.defer(() -> defer.map(PureIOOf::narrowK).get());
  }
}

interface PureIOBracket extends PureIOMonadError, Bracket, E>, E> {

  @Override
  default  PureIO
          bracket(Kind, E>, ? extends A> acquire,
                  Function1, E>, ? extends B>> use,
                  Function1, E>, Unit>> release) {
    return PureIO.bracket(acquire, use, release);
  }
}

interface PureIOMonadDefer
    extends MonadDefer, Throwable>>, PureIODefer, PureIOBracket {

  @SuppressWarnings("rawtypes")
  PureIOMonadDefer INSTANCE = new PureIOMonadDefer() {};

  @Override
  default PureIO sleep(Duration duration) {
    return UIO.sleep(duration).toPureIO();
  }
}

interface PureIOAsync extends Async, Throwable>>, PureIOMonadDefer {

  @SuppressWarnings("rawtypes")
  PureIOAsync INSTANCE = new PureIOAsync() {};
  
  @Override
  default  PureIO asyncF(Function1>, Kind, Throwable>, Unit>> consumer) {
    return PureIO.cancellable((env, cb) -> consumer.andThen(PureIOOf::narrowK).apply(e -> cb.accept(Try.success(e.toEither()))));
  }
}

interface PureIOConcurrent extends Concurrent, Throwable>>, PureIOAsync {
  
  static  PureIOConcurrent instance(Executor executor) {
    return () -> executor;
  }
  
  Executor executor();

  @Override
  default  PureIO, Throwable>, B>>, Tuple2, Throwable>, A>, B>>> racePair(
      Kind, Throwable>, ? extends A> fa, Kind, Throwable>, ? extends B> fb) {
    return PureIO.racePair(executor(), fa, fb);
  }
  
  @Override
  default  PureIO, Throwable>, A>> fork(Kind, Throwable>, ? extends A> value) {
    PureIO fix = value.fix(PureIOOf::narrowK);
    return fix.fork();
  }
}

final class PureIOConsole implements Console, Throwable>> {

  @SuppressWarnings("rawtypes")
  protected static final PureIOConsole INSTANCE = new PureIOConsole();

  private final SystemConsole console = new SystemConsole();

  @Override
  public PureIO readln() {
    return PureIO.task(console::readln);
  }

  @Override
  public PureIO println(String text) {
    return PureIO.exec(() -> console.println(text));
  }
}

interface PureIORuntime extends Runtime, E>> {
  
  static  PureIORuntime instance(R env) {
    return () -> env;
  }

  R env();

  @Override
  default  T run(Kind, E>, T> value) {
    return value.fix(toPureIO()).provide(env()).getRight();
  }
  
  @Override
  default  Sequence run(Sequence, E>, T>> values) {
    return run(PureIO.traverse(values.map(PureIOOf::narrowK)));
  }

  @Override
  default  Future parRun(Kind, E>, T> value, Executor executor) {
    return value.fix(toPureIO()).runAsync(env()).map(Either::get);
  }
  
  @Override
  default  Future> parRun(Sequence, E>, T>> values, Executor executor) {
    return parRun(PureIO.traverse(values.map(PureIOOf::narrowK)), executor);
  }
}