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

com.github.tonivade.purefun.instances.RIOInstances 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.concurrent.FutureOf.toFuture;
import static com.github.tonivade.purefun.effect.RIOOf.toRIO;
import static com.github.tonivade.purefun.instances.FutureInstances.async;

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.Unit;
import com.github.tonivade.purefun.concurrent.Future;
import com.github.tonivade.purefun.effect.RIO;
import com.github.tonivade.purefun.effect.RIOOf;
import com.github.tonivade.purefun.effect.RIO_;
import com.github.tonivade.purefun.effect.UIO;
import com.github.tonivade.purefun.typeclasses.Applicative;
import com.github.tonivade.purefun.typeclasses.Bracket;
import com.github.tonivade.purefun.typeclasses.Console;
import com.github.tonivade.purefun.typeclasses.Defer;
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 RIOInstances {

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

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

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

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

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

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

interface RIOFunctor extends Functor> {

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

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

interface RIOPure extends Applicative> {

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

interface RIOApplicative extends RIOPure {

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

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

interface RIOMonad extends RIOPure, Monad> {

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

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

interface RIOMonadError extends RIOMonad, MonadError, Throwable> {

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

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

  @Override
  default  RIO 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(RIOOf::narrowK);
    Function1> map = RIO::pure;
    RIO urio = RIOOf.narrowK(value);
    return urio.foldM(mapError, map);
  }
}

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

interface RIODefer extends Defer> {

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

interface RIOBracket extends RIOMonadError, Bracket, Throwable> {

  @Override
  default  RIO
          bracket(Kind, ? extends A> acquire,
                  Function1, ? extends B>> use,
                  Consumer1 release) {
    return RIO.bracket(acquire.fix(toRIO()), use.andThen(RIOOf::narrowK), release);
  }
}

interface RIOMonadDefer
    extends MonadDefer>, RIODefer, RIOBracket {

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

  @Override
  default RIO sleep(Duration duration) {
    return UIO.sleep(duration).toRIO();
  }
}

final class RIOConsole implements Console> {

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

  private final SystemConsole console = new SystemConsole();

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

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

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

  R env();

  @Override
  default  T run(Kind, T> value) {
    return value.fix(toRIO()).safeRunSync(env()).getOrElseThrow();
  }

  @Override
  default  Future parRun(Kind, T> value, Executor executor) {
    return value.fix(toRIO()).foldMap(env(), async(executor)).fix(toFuture());
  }
}