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

com.github.tonivade.purefun.instances.TryInstances 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 com.github.tonivade.purefun.Eq;
import com.github.tonivade.purefun.Function1;
import com.github.tonivade.purefun.Function2;
import com.github.tonivade.purefun.Higher1;
import com.github.tonivade.purefun.Instance;
import com.github.tonivade.purefun.Kind;
import com.github.tonivade.purefun.Pattern2;
import com.github.tonivade.purefun.type.Eval;
import com.github.tonivade.purefun.type.Try;
import com.github.tonivade.purefun.typeclasses.Applicative;
import com.github.tonivade.purefun.typeclasses.Foldable;
import com.github.tonivade.purefun.typeclasses.Functor;
import com.github.tonivade.purefun.typeclasses.Monad;
import com.github.tonivade.purefun.typeclasses.MonadError;
import com.github.tonivade.purefun.typeclasses.MonadThrow;
import com.github.tonivade.purefun.typeclasses.Traverse;

public interface TryInstances {

  static  Eq> eq(Eq eqSuccess) {
    final Eq eqFailure = Eq.throwable();
    return (a, b) -> Pattern2., Try, Boolean>build()
      .when((x, y) -> x.isFailure() && y.isFailure())
        .then((x, y) -> eqFailure.eqv(x.getCause(), y.getCause()))
      .when((x, y) -> x.isSuccess() && y.isSuccess())
        .then((x, y) -> eqSuccess.eqv(x.get(), y.get()))
      .otherwise()
        .returns(false)
      .apply(Try.narrowK(a), Try.narrowK(b));
  }

  static Functor functor() {
    return new TryFunctor() {};
  }

  static Applicative applicative() {
    return new TryApplicative() {};
  }

  static Monad monad() {
    return new TryMonad() {};
  }

  static MonadError monadError() {
    return new TryMonadError() {};
  }

  static MonadThrow monadThrow() {
    return new TryMonadThrow() {};
  }

  static Foldable foldable() {
    return new TryFoldable() {};
  }

  static Traverse traverse() {
    return new TryTraverse() {};
  }
}

@Instance
interface TryFunctor extends Functor {

  @Override
  default  Try map(Higher1 value, Function1 mapper) {
    return Try.narrowK(value).map(mapper);
  }
}

@Instance
interface TryPure extends Applicative {

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

@Instance
interface TryApplicative extends TryPure {

  @Override
  default  Try ap(Higher1 value, Higher1> apply) {
    return Try.narrowK(value).flatMap(t -> Try.narrowK(apply).map(f -> f.apply(t)));
  }
}

@Instance
interface TryMonad extends TryPure, Monad {

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

@Instance
interface TryMonadError extends TryMonad, MonadError {

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

  @Override
  default  Try handleErrorWith(Higher1 value,
      Function1> handler) {
    return Try.narrowK(value).fold(handler.andThen(Try::narrowK), Try::success);
  }
}

@Instance
interface TryMonadThrow extends TryMonadError, MonadThrow { }

@Instance
interface TryFoldable extends Foldable {

  @Override
  default  B foldLeft(Higher1 value, B initial, Function2 mapper) {
    return Try.narrowK(value).fold(t -> initial, a -> mapper.apply(initial, a));
  }

  @Override
  default  Eval foldRight(Higher1 value, Eval initial,
      Function2, Eval> mapper) {
    return Try.narrowK(value).fold(t -> initial, a -> mapper.apply(a, initial));
  }
}

@Instance
interface TryTraverse extends Traverse, TryFoldable {

  @Override
  default  Higher1> traverse(
      Applicative applicative, Higher1 value,
      Function1> mapper) {
    return Try.narrowK(value).fold(
        t -> applicative.pure(Try.failure(t)),
        t -> applicative.map(mapper.apply(t), Try::success));
  }
}