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

com.github.tonivade.purefun.instances.IOInstances 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.monad.IOOf.toIO;
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.monad.IO;
import com.github.tonivade.purefun.monad.IOOf;
import com.github.tonivade.purefun.monad.IO_;
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;
import com.github.tonivade.purefun.typeclasses.Timer;

public interface IOInstances {

  static Functor functor() {
    return IOFunctor.INSTANCE;
  }

  static Applicative applicative() {
    return applicative(Future.DEFAULT_EXECUTOR);
  }

  static Applicative applicative(Executor executor) {
    return IOApplicative.instance(executor);
  }

  static Monad monad() {
    return IOMonad.INSTANCE;
  }

  static MonadError monadError() {
    return IOMonadError.INSTANCE;
  }

  static MonadThrow monadThrow() {
    return IOMonadThrow.INSTANCE;
  }

  static Timer timer() {
    return IOMonadDefer.INSTANCE;
  }

  static MonadDefer monadDefer() {
    return IOMonadDefer.INSTANCE;
  }

  static Async async() {
    return IOAsync.INSTANCE;
  }

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

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

  static Console console() {
    return IOConsole.INSTANCE;
  }
  
  static Runtime runtime() {
    return IORuntime.INSTANCE;
  }
}

interface IOFunctor extends Functor {

  IOFunctor INSTANCE = new IOFunctor() {};

  @Override
  default  Kind map(Kind value, Function1 map) {
    return value.fix(toIO()).map(map);
  }
}

interface IOPure extends Applicative {

  @Override
  default  IO pure(T value) {
    return IO.pure(value);
  }
}

interface IOApplicative extends IOPure, Applicative {
  
  static IOApplicative instance(Executor executor) {
    return () -> executor;
  }

  Executor executor();

  @Override
  default  IO ap(Kind value, 
      Kind> apply) {
    return IO.parMap2(executor(), value.fix(toIO()), apply.fix(toIO()), (v, a) -> a.apply(v));
  }
}

interface IOMonad extends Monad, IOPure {

  IOMonad INSTANCE = new IOMonad() {};

  @Override
  default  IO flatMap(
      Kind value, 
      Function1> map) {
    return value.fix(toIO()).flatMap(map.andThen(IOOf::narrowK));
  }
}

interface IOMonadError extends MonadError, IOMonad {

  IOMonadError INSTANCE = new IOMonadError() {};

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

  @Override
  default  IO handleErrorWith(
      Kind value, 
      Function1> handler) {
    return IOOf.narrowK(value).redeemWith(handler.andThen(IOOf::narrowK), IO::pure);
  }
}

interface IOMonadThrow extends MonadThrow, IOMonadError {

  IOMonadThrow INSTANCE = new IOMonadThrow() {};
}

interface IODefer extends Defer {

  @Override
  default  IO defer(Producer> defer) {
    return IO.suspend(defer.map(IOOf::narrowK));
  }
}

interface IOBracket extends IOMonadError, Bracket {

  @Override
  default  IO bracket(
      Kind acquire, 
      Function1> use, 
      Function1> release) {
    return IO.bracket(acquire, use, release);
  }
}

interface IOMonadDefer extends MonadDefer, IODefer, IOBracket {

  IOMonadDefer INSTANCE = new IOMonadDefer() {};

  @Override
  default IO sleep(Duration duration) {
    return IO.sleep(duration);
  }
}

interface IOAsync extends Async, IOMonadDefer {

  IOAsync INSTANCE = new IOAsync() {};
  
  @Override
  default  IO asyncF(Function1>, Kind> consumer) {
    return IO.cancellable(consumer.andThen(IOOf::narrowK));
  }
}

interface IOConcurrent extends Concurrent, IOAsync {
  
  static IOConcurrent instance(Executor executor) {
    return () -> executor;
  }
  
  Executor executor();
  
  @Override
  default  IO>, Tuple2, B>>> racePair(Kind fa, Kind fb) {
    return IO.racePair(executor(), fa, fb);
  }
  
  @Override
  default  IO> fork(Kind value) {
    IO fix = value.fix(IOOf::narrowK);
    return fix.fork();
  }
}

final class IOConsole implements Console {

  public static final IOConsole INSTANCE = new IOConsole();

  private final SystemConsole console = new SystemConsole();

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

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

interface IORuntime extends Runtime {
  
  IORuntime INSTANCE = new IORuntime() {};

  @Override
  default  T run(Kind value) {
    return value.fix(toIO()).unsafeRunSync();
  }
  
  @Override
  default  Sequence run(Sequence> values) {
    return run(IO.traverse(values.map(IOOf::narrowK)));
  }

  @Override
  default  Future parRun(Kind value, Executor executor) {
    return value.fix(toIO()).runAsync(executor);
  }
  
  @Override
  default  Future> parRun(Sequence> values, Executor executor) {
    return parRun(IO.traverse(values.map(IOOf::narrowK)), executor);
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy