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-2019, 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.Unit.unit;
import static java.util.Objects.requireNonNull;

import com.github.tonivade.purefun.Consumer1;
import com.github.tonivade.purefun.Eq;
import com.github.tonivade.purefun.Function1;
import com.github.tonivade.purefun.Higher1;
import com.github.tonivade.purefun.Higher3;
import com.github.tonivade.purefun.Instance;
import com.github.tonivade.purefun.Kind;
import com.github.tonivade.purefun.Producer;
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;

public interface EitherTInstances {

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

  static  Monad, L>> monad(Monad monadF) {
    requireNonNull(monadF);
    return new EitherTMonad() {

      @Override
      public Monad monadF() { return monadF; }
    };
  }

  static  MonadError, L>, L> monadError(Monad monadF) {
    requireNonNull(monadF);
    return new EitherTMonadErrorFromMonad() {

      @Override
      public Monad monadF() { return monadF; }
    };
  }

  static  MonadError, L>, L> monadError(MonadError monadErrorF) {
    requireNonNull(monadErrorF);
    return new EitherTMonadErrorFromMonadError() {

      @Override
      public MonadError monadF() { return monadErrorF; }
    };
  }

  static  MonadThrow, Throwable>> monadThrow(Monad monadF) {
    requireNonNull(monadF);
    return new EitherTMonadThrowFromMonad() {

      @Override
      public Monad monadF() { return monadF; }
    };
  }

  static  MonadThrow, Throwable>> monadThrow(MonadThrow monadF) {
    requireNonNull(monadF);
    return new EitherTMonadThrowFromMonadThrow() {

      @Override
      public MonadThrow monadF() { return monadF; }
    };
  }

  static  Defer, L>> defer(MonadDefer monadDeferF) {
    requireNonNull(monadDeferF);
    return new EitherTDefer() {

      @Override
      public Monad monadF() { return monadDeferF; }

      @Override
      public Defer deferF() { return monadDeferF; }
    };
  }

  static  MonadDefer, Throwable>> monadDeferFromMonad(MonadDefer monadDeferF) {
    requireNonNull(monadDeferF);
    return new EitherTMonadDeferFromMonad() {

      @Override
      public Monad monadF() { return monadDeferF; }

      @Override
      public Defer deferF() { return monadDeferF; }

      @Override
      public Bracket bracketF() { return monadDeferF; }

      @Override
      public  Higher1> acquireRecover(Throwable error) {
        return monadDeferF.pure(Either.left(error));
      }
    };
  }

  static  MonadDefer, Throwable>> monadDeferFromMonadThrow(MonadDefer monadDeferF) {
    requireNonNull(monadDeferF);
    return new EitherTMonadDeferFromMonadThrow() {

      @Override
      public MonadThrow monadF() { return monadDeferF; }

      @Override
      public Defer deferF() { return monadDeferF; }

      @Override
      public Bracket bracketF() { return monadDeferF; }

      @Override
      public  Higher1> acquireRecover(Throwable error) {
        return monadDeferF.raiseError(error);
      }
    };
  }

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

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

@Instance
interface EitherTMonad extends Monad, L>> {

  Monad monadF();

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

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

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

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

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

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

  @Override
  MonadError monadF();

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

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

@Instance
interface EitherTMonadThrowFromMonad
    extends EitherTMonadErrorFromMonad,
            MonadThrow, Throwable>> { }

@Instance
interface EitherTMonadThrowFromMonadThrow
    extends EitherTMonadErrorFromMonadError,
            MonadThrow, Throwable>> { }

@Instance
interface EitherTDefer extends Defer, E>> {

  Monad monadF();
  Defer deferF();

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

@Instance
interface EitherTBracket extends Bracket, Throwable>> {

  Bracket bracketF();
  Monad monadF();
   Higher1> acquireRecover(Throwable error);

  @Override
  default  EitherT
          bracket(Higher1, Throwable>, A> acquire,
                  Function1, Throwable>, B>> use,
                  Consumer1 release) {
    Higher1> bracket =
        bracketF().bracket(
            acquire.fix1(EitherT::narrowK).value(),
            either -> either.fold(
                error -> acquireRecover(error),
                value -> use.andThen(EitherT::narrowK).apply(value).value()),
            either -> either.fold(cons(unit()), release.asFunction()));
    return EitherT.of(monadF(), bracket);
  }
}

@Instance
interface EitherTMonadDeferFromMonad
    extends EitherTMonadThrowFromMonad,
            EitherTDefer,
            EitherTBracket,
            MonadDefer, Throwable>> { }

@Instance
interface EitherTMonadDeferFromMonadThrow
    extends EitherTMonadThrowFromMonadThrow,
            EitherTDefer,
            EitherTBracket,
            MonadDefer, Throwable>> { }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy