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

com.github.tonivade.purefun.instances.MonadMTL 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.Precondition.checkNonNull;
import static com.github.tonivade.purefun.transformer.EitherTOf.toEitherT;
import static com.github.tonivade.purefun.transformer.KleisliOf.toKleisli;
import static com.github.tonivade.purefun.transformer.StateTOf.toStateT;
import com.github.tonivade.purefun.Function1;
import com.github.tonivade.purefun.Kind;
import com.github.tonivade.purefun.Tuple;
import com.github.tonivade.purefun.Tuple2;
import com.github.tonivade.purefun.Unit;
import com.github.tonivade.purefun.Witness;
import com.github.tonivade.purefun.instances.MonadMTL.EffectE;
import com.github.tonivade.purefun.instances.MonadMTL.EffectE_;
import com.github.tonivade.purefun.instances.MonadMTL.EffectR;
import com.github.tonivade.purefun.instances.MonadMTL.EffectR_;
import com.github.tonivade.purefun.instances.MonadMTL.EffectS_;
import com.github.tonivade.purefun.transformer.EitherT;
import com.github.tonivade.purefun.transformer.EitherT_;
import com.github.tonivade.purefun.transformer.Kleisli;
import com.github.tonivade.purefun.transformer.Kleisli_;
import com.github.tonivade.purefun.transformer.StateT;
import com.github.tonivade.purefun.transformer.StateT_;
import com.github.tonivade.purefun.type.Either;
import com.github.tonivade.purefun.typeclasses.Monad;
import com.github.tonivade.purefun.typeclasses.MonadError;
import com.github.tonivade.purefun.typeclasses.MonadReader;
import com.github.tonivade.purefun.typeclasses.MonadState;

public class MonadMTL
    implements Monad, MonadError, MonadState, MonadReader {

  private final Monad monad;
  private final MonadError monadErrorE;
  private final Monad monadR;
  private final MonadError, S>, E> monadErrorS;
  private final MonadReader, S>, R> monadReaderS;
  private final MonadState, S>, S> monadStateS;

  public MonadMTL(Monad monad) {
    this.monad = checkNonNull(monad);
    this.monadErrorE = new EffectEMonadError<>(monad);
    this.monadR = new EffectRMonad<>(monad);
    this.monadErrorS = StateTInstances.monadError(new EffectRMonadError<>(monad));
    this.monadReaderS = StateTInstances.monadReader(new EffectRMonadReader<>(monad));
    this.monadStateS = StateTInstances.monadState(monadR);
  }

  @Override
  public  EffectS pure(A value) {
    return new EffectS<>(monadStateS.pure(value));
  }

  @Override
  public  EffectS flatMap(Kind value,
      Function1> map) {
    return new EffectS<>(monadStateS.flatMap(
        value.fix(EffectS::narrowK).value(),
        x -> map.apply(x).fix(EffectS::narrowK).value()));
  }

  @Override
  public EffectS get() {
    return new EffectS<>(monadStateS.get());
  }

  @Override
  public EffectS set(S state) {
    return new EffectS<>(monadStateS.set(state));
  }

  @Override
  public  EffectS raiseError(E error) {
    return new EffectS<>(monadErrorS.raiseError(error));
  }

  @Override
  public  EffectS handleErrorWith(
      Kind value, Function1> handler) {
    return new EffectS<>(monadErrorS.handleErrorWith(
        value.fix(EffectS::narrowK).value(),
        error -> handler.apply(error).fix(EffectS::narrowK).value()));
  }

  @Override
  public EffectS ask() {
    return new EffectS<>(monadReaderS.ask());
  }

  public  EffectE effectE(Kind> value) {
    return new EffectE<>(EitherT.of(monad, value));
  }

  public  EffectR effectR(EffectE effect0) {
    return new EffectR<>(Kleisli.of(monadErrorE, config -> effect0));
  }

  public  EffectS effectS(EffectR effect1) {
    return new EffectS<>(StateT.state(monadR, state -> monadR.map(effect1, x -> Tuple.of(state, x))));
  }

  public  EffectS effect(Kind> value) {
    return effectS(effectR(effectE(value)));
  }

  public static final class EffectE_ implements Witness { }
  public static final class EffectR_ implements Witness { }
  public static final class EffectS_ implements Witness { }

  public static final class EffectE implements Kind {

    private final EitherT value;

    public EffectE(Kind, E>, A> value) {
      this.value = value.fix(toEitherT());
    }

    public EitherT value() {
      return value;
    }

    public Kind> run() {
      return value.value();
    }

    @SuppressWarnings("unchecked")
    public static  EffectE narrowK(Kind hkt) {
      return (EffectE) hkt;
    }
  }

  public static final class EffectR implements Kind {

    private final Kleisli value;

    public EffectR(Kind, R>, A> value) {
      this.value = value.fix(toKleisli());
    }

    public Kleisli value() {
      return value;
    }

    public EffectE run(R config) {
      return value.run(config).fix(EffectE::narrowK);
    }

    @SuppressWarnings("unchecked")
    public static  EffectR narrowK(Kind hkt) {
      return (EffectR) hkt;
    }
  }

  public static final class EffectS implements Kind {

    private final StateT value;

    public EffectS(Kind, S>, A> value) {
      this.value = value.fix(toStateT());
    }

    public StateT value() {
      return value;
    }

    public EffectR> run(S state) {
      return value.run(state).fix(EffectR::narrowK);
    }

    @SuppressWarnings("unchecked")
    public static  EffectS narrowK(Kind hkt) {
      return (EffectS) hkt;
    }
  }
}

class EffectEMonadError implements MonadError {

  private final MonadError, E>, E> monad;

  public EffectEMonadError(Monad monad) {
    this.monad = EitherTInstances.monadError(monad);
  }

  @Override
  public  EffectE pure(A value) {
    return new EffectE<>(monad.pure(value));
  }

  @Override
  public  EffectE flatMap(Kind value,
      Function1> map) {
    return new EffectE<>(monad.flatMap(
        value.fix(EffectE::narrowK).value(),
        x -> map.apply(x).fix(EffectE::narrowK).value()));
  }

  @Override
  public  EffectE raiseError(E error) {
    return new EffectE<>(monad.raiseError(error));
  }

  @Override
  public  EffectE handleErrorWith(Kind value,
      Function1> handler) {
    return new EffectE<>(monad.handleErrorWith(value.fix(EffectE::narrowK).value(),
            error -> handler.apply(error).fix(EffectE::narrowK).value()));
  }
}

class EffectRMonad implements Monad {

  private final Monad, R>> monad;

  public EffectRMonad(Monad monad) {
    this.monad = KleisliInstances.monad(new EffectEMonadError(monad));
  }


  @Override
  public  EffectR pure(A value) {
    return new EffectR<>(monad.pure(value));
  }

  @Override
  public  EffectR flatMap(Kind value,
      Function1> map) {
    return new EffectR<>(monad.flatMap(value.fix(EffectR::narrowK).value(),
        t -> map.apply(t).fix(EffectR::narrowK).value()));
  }
}

class EffectRMonadReader extends EffectRMonad implements MonadReader {

  private final MonadReader, R>, R> monad;

  public EffectRMonadReader(Monad monad) {
    super(monad);
    this.monad = KleisliInstances.monadReader(new EffectEMonadError(monad));
  }

  @Override
  public EffectR ask() {
    return new EffectR<>(monad.ask());
  }
}

class EffectRMonadError extends EffectRMonad implements MonadError {

  private final MonadError, R>, E> monadError;

  public EffectRMonadError(Monad monad) {
    super(monad);
    this.monadError = KleisliInstances.monadError(new EffectEMonadError(monad));
  }

  @Override
  public  EffectR raiseError(E error) {
    return new EffectR<>(monadError.raiseError(error));
  }

  @Override
  public  EffectR handleErrorWith(
      Kind value, Function1> handler) {
    return new EffectR<>(monadError.handleErrorWith(
        value.fix(EffectR::narrowK).value(),
        error -> handler.apply(error).fix(EffectR::narrowK).value()));
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy