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

com.github.tonivade.purefun.instances.URIOInstances 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.URIOOf.toURIO;
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.URIO;
import com.github.tonivade.purefun.effect.URIOOf;
import com.github.tonivade.purefun.effect.URIO_;
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 URIOInstances {

  static  Functor> functor() {
    return URIOFunctor.INSTANCE;
  }

  static  Applicative> applicative() {
    return URIOApplicative.INSTANCE;
  }

  static  Monad> monad() {
    return URIOMonad.INSTANCE;
  }

  static  MonadThrow> monadThrow() {
    return URIOMonadThrow.INSTANCE;
  }

  static  MonadDefer> monadDefer() {
    return URIOMonadDefer.INSTANCE;
  }

  static  Async> async() {
    return URIOAsync.INSTANCE;
  }

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

  static  Concurrent> concurrent(Executor executor) {
    return URIOConcurrent.instance(executor);
  }

  static  Console, Throwable>> console() {
    return URIOConsole.INSTANCE;
  }
  
  static  Runtime> runtime(R env) {
    return URIORuntime.instance(env);
  }
}

interface URIOFunctor extends Functor> {

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

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

interface URIOPure extends Applicative> {

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

interface URIOApplicative extends URIOPure {

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

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

interface URIOMonad extends URIOPure, Monad> {

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

  @Override
  default  URIO
          flatMap(Kind, ? extends A> value,
                  Function1, ? extends B>> map) {
    return value.fix(toURIO()).flatMap(map.andThen(URIOOf::narrowK));
  }
}

interface URIOMonadError extends URIOMonad, MonadError, Throwable> {

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

  @Override
  default  URIO raiseError(Throwable error) {
    return URIO.raiseError(error);
  }

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

interface URIOMonadThrow
    extends URIOMonadError,
            MonadThrow> {
  @SuppressWarnings("rawtypes")
  URIOMonadThrow INSTANCE = new URIOMonadThrow() {};
}

interface URIODefer extends Defer> {

  @Override
  default  URIO
          defer(Producer, ? extends A>> defer) {
    return URIO.defer(defer::get);
  }
}

interface URIOBracket extends URIOMonadError, Bracket, Throwable> {

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

interface URIOMonadDefer
    extends MonadDefer>, URIODefer, URIOBracket {

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

  @Override
  default URIO sleep(Duration duration) {
    return UIO.sleep(duration).toURIO();
  }
}

interface URIOAsync extends Async>, URIOMonadDefer {

  @SuppressWarnings("rawtypes")
  URIOAsync INSTANCE = new URIOAsync() {};
  
  @Override
  default  URIO asyncF(Function1>, Kind, Unit>> consumer) {
    return URIO.cancellable((env, cb) -> consumer.andThen(URIOOf::narrowK).apply(cb));
  }
}

interface URIOConcurrent extends URIOAsync, Concurrent> {
  
  static  URIOConcurrent instance(Executor executor) {
    return () -> executor;
  }
  
  Executor executor();
  
  @Override
  default  URIO, B>>, Tuple2, A>, B>>> racePair(
    Kind, ? extends A> fa, Kind, ? extends B> fb) {
    return URIO.racePair(executor(), fa, fb);
  }
  
  @Override
  default  URIO, A>> fork(Kind, ? extends A> value) {
    URIO fix = value.fix(URIOOf::narrowK);
    return fix.fork();
  }
  
}

final class URIOConsole implements Console> {

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

  private final SystemConsole console = new SystemConsole();

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

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

interface URIORuntime extends Runtime> {
  
  static  URIORuntime instance(R env) {
    return () -> env;
  }

  R env();

  @Override
  default  T run(Kind, T> value) {
    return value.fix(toURIO()).safeRunSync(env()).getOrElseThrow();
  }
  
  @Override
  default  Sequence run(Sequence, T>> values) {
    return run(URIO.traverse(values.map(URIOOf::narrowK)));
  }

  @Override
  default  Future parRun(Kind, T> value, Executor executor) {
    return value.fix(toURIO()).runAsync(env());
  }
  
  @Override
  default  Future> parRun(Sequence, T>> values, Executor executor) {
    return parRun(URIO.traverse(values.map(URIOOf::narrowK)), executor);
  }
}