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

com.github.tonivade.purefun.instances.OptionTInstances 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.Unit.unit;
import static java.util.Objects.requireNonNull;

import java.util.NoSuchElementException;

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.Higher2;
import com.github.tonivade.purefun.Instance;
import com.github.tonivade.purefun.Kind;
import com.github.tonivade.purefun.Producer;
import com.github.tonivade.purefun.Unit;
import com.github.tonivade.purefun.transformer.OptionT;
import com.github.tonivade.purefun.type.Option;
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 OptionTInstances {

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

  static  Monad> monad(Monad monadF) {
    requireNonNull(monadF);
    return new OptionTMonad() {

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

  static  MonadError, Unit> monadError(Monad monadF) {
    requireNonNull(monadF);
    return new OptionTMonadErrorFromMonad() {

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

  static  MonadError, E> monadError(MonadError monadErrorF) {
    requireNonNull(monadErrorF);
    return new OptionTMonadErrorFromMonadError() {

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

  static  MonadThrow> monadThrow(MonadThrow monadThrowF) {
    requireNonNull(monadThrowF);
    return new OptionTMonadThrow() {

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

  static  Defer> defer(MonadDefer monadDeferF) {
    requireNonNull(monadDeferF);
    return new OptionTDefer() {

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

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

  static  MonadDefer> monadDefer(MonadDefer monadDeferF) {
    return new OptionTMonadDefer() {

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

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

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

  static  Reference, A> ref(MonadDefer monadF, A value) {
    return Reference.of(monadDefer(monadF), value);
  }
}

@Instance
interface OptionTMonad extends Monad> {

  Monad monadF();

  @Override
  default  OptionT pure(T value) {
    return OptionT.some(monadF(), value);
  }

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

@Instance
interface OptionTMonadErrorFromMonad
    extends MonadError, Unit>, OptionTMonad {

  @Override
  default  OptionT raiseError(Unit error) {
    return OptionT.none(monadF());
  }

  @Override
  default  OptionT handleErrorWith(Higher1, A> value,
      Function1, A>> handler) {
    return OptionT.of(monadF(),
        monadF().flatMap(OptionT.narrowK(value).value(),
            option -> option.fold(() -> handler.andThen(OptionT::narrowK).apply(unit()).value(),
                a -> monadF().pure(Option.some(a)))));
  }
}

@Instance
interface OptionTMonadErrorFromMonadError
    extends MonadError, E>, OptionTMonad {

  @Override
  MonadError monadF();

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

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

@Instance
interface OptionTMonadThrow
    extends MonadThrow>,
            OptionTMonadErrorFromMonadError { }

@Instance
interface OptionTDefer extends Defer> {

  Monad monadF();
  Defer deferF();

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

@Instance
interface OptionTBracket extends Bracket> {

  MonadThrow monadF();
  Defer deferF();
  Bracket bracketF();

  @Override
  default  OptionT bracket(Higher1, A> acquire,
                                       Function1, B>> use,
                                       Consumer1 release) {
    Higher1> bracket =
        bracketF().bracket(
            acquire.fix1(OptionT::narrowK).value(),
            option -> option.fold(
                () -> monadF().raiseError(new NoSuchElementException("could not acquire resource")),
                value -> use.andThen(OptionT::narrowK).apply(value).value()),
            option -> option.fold(() -> unit(), release.asFunction()));
    return OptionT.of(monadF(), bracket);
  }
}

@Instance
interface OptionTMonadDefer
    extends OptionTMonadThrow,
            OptionTDefer,
            OptionTBracket,
            MonadDefer> { }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy