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

com.github.tonivade.purefun.instances.EitherTInstances 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.Function1.cons;
import static com.github.tonivade.purefun.Function1.identity;
import static com.github.tonivade.purefun.Precondition.checkNonNull;
import static com.github.tonivade.purefun.Unit.unit;

import java.time.Duration;

import com.github.tonivade.purefun.Eq;
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.Witness;
import com.github.tonivade.purefun.transformer.EitherT;
import com.github.tonivade.purefun.transformer.EitherTOf;
import com.github.tonivade.purefun.transformer.EitherT_;
import com.github.tonivade.purefun.type.Either;
import com.github.tonivade.purefun.typeclasses.Bracket;
import com.github.tonivade.purefun.typeclasses.Defer;
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.Reference;
import com.github.tonivade.purefun.typeclasses.Timer;

public interface EitherTInstances {

  static  Eq, L>, R>> eq(Eq>> eq) {
    return (a, b) -> eq.eqv(EitherTOf.narrowK(a).value(), EitherTOf.narrowK(b).value());
  }

  static  Monad, L>> monad(Monad monadF) {
    return EitherTMonad.instance(checkNonNull(monadF));
  }

  static  MonadError, L>, L> monadError(Monad monadF) {
    return EitherTMonadErrorFromMonad.instance(checkNonNull(monadF));
  }

  static  MonadError, L>, L> monadError(MonadError monadErrorF) {
    return EitherTMonadErrorFromMonadError.instance(checkNonNull(monadErrorF));
  }

  static  MonadThrow, Throwable>> monadThrow(Monad monadF) {
    return EitherTMonadThrowFromMonad.instance(checkNonNull(monadF));
  }

  static  MonadThrow, Throwable>> monadThrow(MonadThrow monadF) {
    return EitherTMonadThrowFromMonadThrow.instance(checkNonNull(monadF));
  }

  static  MonadDefer, Throwable>> monadDefer(MonadDefer monadDeferF) {
    return EitherTMonadDefer.instance(checkNonNull(monadDeferF));
  }

  static 
         Reference, Throwable>, A>
         refFromMonadThrow(MonadDefer monadDeferF, A value) {
    return Reference.of(monadDefer(monadDeferF), value);
  }
}

interface EitherTMonad extends Monad, L>> {

  static  EitherTMonad instance(Monad monadF) {
    return () -> monadF;
  }

  Monad monadF();

  @Override
  default  EitherT pure(T value) {
    return EitherT.right(monadF(), value);
  }

  @Override
  default  EitherT flatMap(Kind, L>, ? extends T> value,
      Function1, L>, ? extends R>> map) {
    return EitherTOf.narrowK(value).flatMap(map.andThen(EitherTOf::narrowK));
  }
}

interface EitherTMonadErrorFromMonad
    extends MonadError, E>, E>, EitherTMonad {

  static  EitherTMonadErrorFromMonad instance(Monad monadF) {
    return () -> monadF;
  }

  @Override
  default  EitherT raiseError(E error) {
    return EitherT.left(monadF(), error);
  }

  @Override
  default  EitherT handleErrorWith(Kind, E>, A> value,
      Function1, E>, ? extends A>> handler) {
    return EitherT.of(monadF(),
        monadF().flatMap(EitherTOf.narrowK(value).value(),
            either -> either.fold(
                e -> handler.andThen(EitherTOf::narrowK).apply(e).value(),
                a -> monadF().pure(Either.right(a)))));
  }
}

interface EitherTMonadErrorFromMonadError
    extends MonadError, E>, E>,
            EitherTMonad {

  static  EitherTMonadErrorFromMonadError instance(MonadError monadErrorF) {
    return () -> monadErrorF;
  }

  @Override
  MonadError monadF();

  @Override
  default  EitherT raiseError(E error) {
    return EitherT.of(monadF(), monadF().raiseError(error));
  }

  @Override
  default  EitherT handleErrorWith(Kind, E>, A> value,
      Function1, E>, ? extends A>> handler) {
    return EitherT.of(monadF(),
                      monadF().handleErrorWith(EitherTOf.narrowK(value).value(),
                                               error -> handler.andThen(EitherTOf::narrowK).apply(error).value()));
  }
}

interface EitherTMonadThrowFromMonad
    extends EitherTMonadErrorFromMonad,
            MonadThrow, Throwable>> {

  static  EitherTMonadThrowFromMonad instance(Monad monadF) {
    return () -> monadF;
  }
}

interface EitherTMonadThrowFromMonadThrow
    extends EitherTMonadErrorFromMonadError,
            MonadThrow, Throwable>> {

  static  EitherTMonadThrowFromMonadThrow instance(MonadThrow monadThrowF) {
    return () -> monadThrowF;
  }
}

interface EitherTDefer extends Defer, E>> {

  MonadDefer monadF();

  @Override
  default  EitherT defer(Producer, E>, ? extends A>> defer) {
    return EitherT.of(monadF(), monadF().defer(() -> defer.map(EitherTOf::narrowK).get().value()));
  }
}

interface EitherTBracket extends Bracket, E>, E> {

  MonadDefer monadF();

   Kind> acquireRecover(E error);

  @Override
  default  EitherT
          bracket(Kind, E>, ? extends A> acquire,
                  Function1, E>, ? extends B>> use,
                  Function1, E>, Unit>> release) {
    Kind> bracket =
        monadF().bracket(
            acquire.fix(EitherTOf::narrowK).value(),
            either -> either.fold(
                this::acquireRecover,
                value -> use.andThen(EitherTOf::narrowK).apply(value).value()),
            either -> {
              Kind, E>, Unit> fold = either.fold(error -> EitherT.left(monadF(), error), release::apply);
              Kind> value = fold.fix(EitherTOf::narrowK).value();
              return monadF().map(value, x -> x.fold(cons(unit()), identity()));
            });
    return EitherT.of(monadF(), bracket);
  }
}

interface EitherTTimer extends Timer, Throwable>> {
  
  MonadDefer monadF();

  @Override
  default EitherT sleep(Duration duration) {
    return EitherT.of(monadF(), monadF().map(monadF().sleep(duration), Either::right));
  }
}

interface EitherTMonadDefer
    extends EitherTMonadThrowFromMonadThrow,
            EitherTDefer,
            EitherTBracket,
            EitherTTimer,
            MonadDefer, Throwable>> {

  static  EitherTMonadDefer instance(MonadDefer monadDeferF) {
    return () -> monadDeferF;
  }

  @Override
  default  Kind> acquireRecover(Throwable error) {
    return monadF().raiseError(error);
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy