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

cats.instances.try.scala Maven / Gradle / Ivy

The newest version!
package cats
package instances

import TryInstances.castFailure

import scala.util.control.NonFatal
import scala.util.{Failure, Success, Try}
import scala.annotation.tailrec

trait TryInstances extends TryInstances1 {

  // scalastyle:off method.length
  implicit def catsStdInstancesForTry
    : MonadError[Try, Throwable] with CoflatMap[Try] with Traverse[Try] with Monad[Try] =
    new TryCoflatMap with MonadError[Try, Throwable] with Traverse[Try] with Monad[Try] {
      def pure[A](x: A): Try[A] = Success(x)

      override def product[A, B](ta: Try[A], tb: Try[B]): Try[(A, B)] = (ta, tb) match {
        case (Success(a), Success(b)) => Success((a, b))
        case (f: Failure[_], _)       => castFailure[(A, B)](f)
        case (_, f: Failure[_])       => castFailure[(A, B)](f)
      }

      override def map2[A, B, Z](ta: Try[A], tb: Try[B])(f: (A, B) => Z): Try[Z] = (ta, tb) match {
        case (Success(a), Success(b)) => Try(f(a, b))
        case (f: Failure[_], _)       => castFailure[Z](f)
        case (_, f: Failure[_])       => castFailure[Z](f)
      }

      override def map2Eval[A, B, Z](ta: Try[A], tb: Eval[Try[B]])(f: (A, B) => Z): Eval[Try[Z]] =
        ta match {
          case f: Failure[_] => Now(castFailure[Z](f))
          case Success(a)    => tb.map(_.map(f(a, _)))
        }

      def flatMap[A, B](ta: Try[A])(f: A => Try[B]): Try[B] = ta.flatMap(f)

      def foldLeft[A, B](fa: Try[A], b: B)(f: (B, A) => B): B =
        fa match {
          case Success(a) => f(b, a)
          case Failure(_) => b
        }

      def foldRight[A, B](fa: Try[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] =
        fa match {
          case Success(a) => f(a, lb)
          case Failure(_) => lb
        }

      def traverse[G[_], A, B](fa: Try[A])(f: A => G[B])(implicit G: Applicative[G]): G[Try[B]] =
        fa match {
          case Success(a)    => G.map(f(a))(Success(_))
          case f: Failure[_] => G.pure(castFailure[B](f))
        }

      @tailrec final def tailRecM[B, C](b: B)(f: B => Try[Either[B, C]]): Try[C] =
        f(b) match {
          case f: Failure[_]     => castFailure[C](f)
          case Success(Left(b1)) => tailRecM(b1)(f)
          case Success(Right(c)) => Success(c)
        }

      def handleErrorWith[A](ta: Try[A])(f: Throwable => Try[A]): Try[A] =
        ta.recoverWith { case t => f(t) }

      def raiseError[A](e: Throwable): Try[A] = Failure(e)

      override def handleError[A](ta: Try[A])(f: Throwable => A): Try[A] =
        ta.recover { case t => f(t) }

      override def attempt[A](ta: Try[A]): Try[Either[Throwable, A]] =
        ta match { case Success(a) => Success(Right(a)); case Failure(e) => Success(Left(e)) }

      override def redeem[A, B](ta: Try[A])(recover: Throwable => B, map: A => B): Try[B] =
        ta match { case Success(a) => Try(map(a)); case Failure(e) => Try(recover(e)) }

      override def redeemWith[A, B](ta: Try[A])(recover: Throwable => Try[B], bind: A => Try[B]): Try[B] =
        try ta match {
          case Success(a) => bind(a); case Failure(e) => recover(e)
        } catch { case NonFatal(e) => Failure(e) }

      override def recover[A](ta: Try[A])(pf: PartialFunction[Throwable, A]): Try[A] =
        ta.recover(pf)

      override def recoverWith[A](ta: Try[A])(pf: PartialFunction[Throwable, Try[A]]): Try[A] = ta.recoverWith(pf)

      override def fromTry[A](t: Try[A])(implicit ev: Throwable <:< Throwable): Try[A] = t

      override def map[A, B](ta: Try[A])(f: A => B): Try[B] = ta.map(f)

      override def reduceLeftToOption[A, B](fa: Try[A])(f: A => B)(g: (B, A) => B): Option[B] =
        fa.map(f).toOption

      override def reduceRightToOption[A, B](fa: Try[A])(f: A => B)(g: (A, Eval[B]) => Eval[B]): Eval[Option[B]] =
        Now(fa.map(f).toOption)

      override def reduceLeftOption[A](fa: Try[A])(f: (A, A) => A): Option[A] =
        fa.toOption

      override def reduceRightOption[A](fa: Try[A])(f: (A, Eval[A]) => Eval[A]): Eval[Option[A]] =
        Now(fa.toOption)

      override def get[A](fa: Try[A])(idx: Long): Option[A] =
        if (idx == 0L) fa.toOption else None

      override def size[A](fa: Try[A]): Long =
        fa match {
          case Failure(_) => 0L
          case Success(_) => 1L
        }

      override def find[A](fa: Try[A])(f: A => Boolean): Option[A] =
        fa.toOption.filter(f)

      override def foldMap[A, B](fa: Try[A])(f: A => B)(implicit B: Monoid[B]): B =
        fa match {
          case Failure(_) => B.empty
          case Success(a) => f(a)
        }

      override def exists[A](fa: Try[A])(p: A => Boolean): Boolean =
        fa match {
          case Failure(_) => false
          case Success(a) => p(a)
        }

      override def forall[A](fa: Try[A])(p: A => Boolean): Boolean =
        fa match {
          case Failure(_) => true
          case Success(a) => p(a)
        }

      override def toList[A](fa: Try[A]): List[A] =
        fa match {
          case Failure(_) => Nil
          case Success(a) => a :: Nil
        }

      override def isEmpty[A](fa: Try[A]): Boolean = fa.isFailure

      override def catchNonFatal[A](a: => A)(implicit ev: Throwable <:< Throwable): Try[A] = Try(a)

      override def catchNonFatalEval[A](a: Eval[A])(implicit ev: Throwable <:< Throwable): Try[A] = Try(a.value)
    }
  // scalastyle:on method.length

  implicit def catsStdShowForTry[A](implicit A: Show[A]): Show[Try[A]] =
    new Show[Try[A]] {
      def show(fa: Try[A]): String = fa match {
        case Success(a) => s"Success(${A.show(a)})"
        case Failure(e) => s"Failure($e)"
      }
    }

  /**
   * you may wish to do equality by making `implicit val eqT: Eq[Throwable] = Eq.allEqual`
   * doing a fine grained equality on Throwable can make the code very execution
   * order dependent
   */
  implicit def catsStdEqForTry[A, T](implicit A: Eq[A], T: Eq[Throwable]): Eq[Try[A]] =
    new Eq[Try[A]] {
      def eqv(x: Try[A], y: Try[A]): Boolean = (x, y) match {
        case (Success(a), Success(b)) => A.eqv(a, b)
        case (Failure(a), Failure(b)) => T.eqv(a, b)
        case _                        => false
      }
    }
}

private[instances] object TryInstances {

  /**
   * A `Failure` can be statically typed as `Try[A]` for all `A`, because it
   * does not actually contain an `A` value (as `Success[A]` does).
   */
  @inline final def castFailure[A](f: Failure[_]): Try[A] = f.asInstanceOf[Try[A]]
}

sealed private[instances] trait TryInstances1 extends TryInstances2 {
  implicit def catsStdMonoidForTry[A: Monoid]: Monoid[Try[A]] =
    new TryMonoid[A]
}

sealed private[instances] trait TryInstances2 {
  implicit def catsStdSemigroupForTry[A: Semigroup]: Semigroup[Try[A]] =
    new TrySemigroup[A]
}

abstract private[cats] class TryCoflatMap extends CoflatMap[Try] {
  def map[A, B](ta: Try[A])(f: A => B): Try[B] = ta.map(f)
  def coflatMap[A, B](ta: Try[A])(f: Try[A] => B): Try[B] = Try(f(ta))
}

private[cats] class TrySemigroup[A: Semigroup] extends ApplySemigroup[Try, A](try_.catsStdInstancesForTry, implicitly)

private[cats] class TryMonoid[A](implicit A: Monoid[A])
    extends ApplicativeMonoid[Try, A](try_.catsStdInstancesForTry, implicitly)




© 2015 - 2024 Weber Informatics LLC | Privacy Policy