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

cats.data.XorT.scala Maven / Gradle / Ivy

package cats
package data

import cats.functor.Bifunctor

/**
 * Transformer for `Xor`, allowing the effect of an arbitrary type constructor `F` to be combined with the
 * fail-fast effect of `Xor`.
 *
 * `XorT[F, A, B]` wraps a value of type `F[A Xor B]`. An `F[C]` can be lifted in to `XorT[F, A, C]` via `XorT.right`,
 * and lifted in to a `XorT[F, C, B]` via `XorT.left`.
 */
case class XorT[F[_], A, B](value: F[A Xor B]) {

  def fold[C](fa: A => C, fb: B => C)(implicit F: Functor[F]): F[C] = F.map(value)(_.fold(fa, fb))

  def isLeft(implicit F: Functor[F]): F[Boolean] = F.map(value)(_.isLeft)

  def isRight(implicit F: Functor[F]): F[Boolean] = F.map(value)(_.isRight)

  def swap(implicit F: Functor[F]): XorT[F, B, A] = XorT(F.map(value)(_.swap))

  def getOrElse[BB >: B](default: => BB)(implicit F: Functor[F]): F[BB] = F.map(value)(_.getOrElse(default))

  def recover(pf: PartialFunction[A, B])(implicit F: Functor[F]): XorT[F, A, B] =
    XorT(F.map(value)(_.recover(pf)))

  def recoverWith(pf: PartialFunction[A, XorT[F, A, B]])(implicit F: Monad[F]): XorT[F, A, B] =
    XorT(F.flatMap(value) { xor =>
      xor match {
        case Xor.Left(a) if pf.isDefinedAt(a) => pf(a).value
        case _                                => F.pure(xor)
      }
    })

  def forall(f: B => Boolean)(implicit F: Functor[F]): F[Boolean] = F.map(value)(_.forall(f))

  def exists(f: B => Boolean)(implicit F: Functor[F]): F[Boolean] = F.map(value)(_.exists(f))

  def toEither(implicit F: Functor[F]): F[Either[A, B]] = F.map(value)(_.toEither)

  def toOption(implicit F: Functor[F]): OptionT[F, B] = OptionT(F.map(value)(_.toOption))

  def to[G[_]](implicit functorF: Functor[F], monoidKG: MonoidK[G], applicativeG: Applicative[G]): F[G[B]] =
    functorF.map(value)(_.to[G, B])

  def collectRight(implicit F: MonadCombine[F]): F[B] =
    F.flatMap(value)(_.to[F, B])

  def bimap[C, D](fa: A => C, fb: B => D)(implicit F: Functor[F]): XorT[F, C, D] = XorT(F.map(value)(_.bimap(fa, fb)))

  def applyAlt[D](ff: XorT[F, A, B => D])(implicit F: Apply[F]): XorT[F, A, D] =
    XorT[F, A, D](F.map2(this.value, ff.value)((xb, xbd) => Apply[A Xor ?].ap(xb)(xbd)))

  def flatMap[AA >: A, D](f: B => XorT[F, AA, D])(implicit F: Monad[F]): XorT[F, AA, D] =
    XorT(F.flatMap(value) {
      case l @ Xor.Left(_) => F.pure(l)
      case Xor.Right(b) => f(b).value
    })

  def flatMapF[AA >: A, D](f: B => F[AA Xor D])(implicit F: Monad[F]): XorT[F, AA, D] =
    flatMap(f andThen XorT.apply)

  def map[D](f: B => D)(implicit F: Functor[F]): XorT[F, A, D] = bimap(identity, f)

  def leftMap[C](f: A => C)(implicit F: Functor[F]): XorT[F, C, B] = bimap(f, identity)

  def compare(that: XorT[F, A, B])(implicit o: Order[F[A Xor B]]): Int =
    o.compare(value, that.value)

  def partialCompare(that: XorT[F, A, B])(implicit p: PartialOrder[F[A Xor B]]): Double =
    p.partialCompare(value, that.value)

  def ===(that: XorT[F, A, B])(implicit eq: Eq[F[A Xor B]]): Boolean =
    eq.eqv(value, that.value)

  def traverse[G[_], D](f: B => G[D])(implicit traverseF: Traverse[F], traverseXorA: Traverse[A Xor ?], applicativeG: Applicative[G]): G[XorT[F, A, D]] =
    applicativeG.map(traverseF.traverse(value)(axb => traverseXorA.traverse(axb)(f)))(XorT.apply)

  def foldLeft[C](c: C)(f: (C, B) => C)(implicit F: Foldable[F]): C =
    F.foldLeft(value, c)((c, axb) => axb.foldLeft(c)(f))

  def foldRight[C](lc: Eval[C])(f: (B, Eval[C]) => Eval[C])(implicit F: Foldable[F]): Eval[C] =
    F.foldRight(value, lc)((axb, lc) => axb.foldRight(lc)(f))

  def merge[AA >: A](implicit ev: B <:< AA, F: Functor[F]): F[AA] = F.map(value)(_.fold(identity, ev.apply))

  def combine(that: XorT[F, A, B])(implicit F: Apply[F], A: Semigroup[A], B: Semigroup[B]): XorT[F, A, B] =
    XorT(F.map2(this.value, that.value)(_ combine _))

  def toValidated(implicit F: Functor[F]): F[Validated[A, B]] =
    F.map(value)(_.toValidated)

  /** Run this value as a `[[Validated]]` against the function and convert it back to an `[[XorT]]`.
   *
   * The [[Applicative]] instance for `XorT` "fails fast" - it is often useful to "momentarily" have
   * it accumulate errors instead, which is what the `[[Validated]]` data type gives us.
   *
   * Example:
   * {{{
   * val v1: Validated[NonEmptyList[Error], Int] = ...
   * val v2: Validated[NonEmptyList[Error], Int] = ...
   * val xort: XorT[Error, Int] = ...
   *
   * val result: XorT[NonEmptyList[Error], Int] =
   *   xort.withValidated { v3 => (v1 |@| v2 |@| v3.leftMap(NonEmptyList(_))) { case (i, j, k) => i + j + k } }
   * }}}
   */
  def withValidated[AA, BB](f: Validated[A, B] => Validated[AA, BB])(implicit F: Functor[F]): XorT[F, AA, BB] =
    XorT(F.map(value)(xor => f(xor.toValidated).toXor))

  def show(implicit show: Show[F[A Xor B]]): String = show.show(value)
}

object XorT extends XorTInstances with XorTFunctions

trait XorTFunctions {
  final def left[F[_], A, B](fa: F[A])(implicit F: Functor[F]): XorT[F, A, B] = XorT(F.map(fa)(Xor.left))

  final def right[F[_], A, B](fb: F[B])(implicit F: Functor[F]): XorT[F, A, B] = XorT(F.map(fb)(Xor.right))

  final def pure[F[_], A, B](b: B)(implicit F: Applicative[F]): XorT[F, A, B] = right(F.pure(b))

  /** Transforms an `Xor` into an `XorT`, lifted into the specified `Applicative`.
   *
   * Note: The return type is a FromXorPartiallyApplied[F], which has an apply method
   * on it, allowing you to call fromXor like this:
   * {{{
   * val t: Xor[String, Int] = ...
   * val x: XorT[Option, String, Int] = fromXor[Option](t)
   * }}}
   *
   * The reason for the indirection is to emulate currying type parameters.
   */
  final def fromXor[F[_]]: FromXorPartiallyApplied[F] = new FromXorPartiallyApplied

  final class FromXorPartiallyApplied[F[_]] private[XorTFunctions] {
    def apply[E, A](xor: Xor[E, A])(implicit F: Applicative[F]): XorT[F, E, A] =
      XorT(F.pure(xor))
  }
}

private[data] abstract class XorTInstances extends XorTInstances1 {

  /* TODO violates right absorbtion, right distributivity, and left distributivity -- re-enable when MonadCombine laws are split in to weak/strong
  implicit def xorTMonadCombine[F[_], L](implicit F: Monad[F], L: Monoid[L]): MonadCombine[XorT[F, L, ?]] = {
    implicit val F0 = F
    implicit val L0 = L
    new XorTMonadCombine[F, L] { implicit val F = F0; implicit val L = L0 }
  }
  */

  implicit def xorTEq[F[_], L, R](implicit e: Eq[F[L Xor R]]): Eq[XorT[F, L, R]] =
    // TODO Use Eq.instance on next algebra upgrade
    new Eq[XorT[F, L, R]] {
      def eqv(x: XorT[F, L, R], y: XorT[F, L, R]): Boolean = e.eqv(x.value, y.value)
    }

  implicit def xorTShow[F[_], L, R](implicit sh: Show[F[L Xor R]]): Show[XorT[F, L, R]] =
    functor.Contravariant[Show].contramap(sh)(_.value)

  implicit def xorTBifunctor[F[_]](implicit F: Functor[F]): Bifunctor[XorT[F, ?, ?]] = {
    new Bifunctor[XorT[F, ?, ?]] {
      override def bimap[A, B, C, D](fab: XorT[F, A, B])(f: A => C, g: B => D): XorT[F, C, D] = fab.bimap(f, g)
    }
  }

}

private[data] abstract class XorTInstances1 extends XorTInstances2 {
  /* TODO violates monadFilter right empty law -- re-enable when MonadFilter laws are split in to weak/strong
  implicit def xorTMonadFilter[F[_], L](implicit F: Monad[F], L: Monoid[L]): MonadFilter[XorT[F, L, ?]] = {
    implicit val F0 = F
    implicit val L0 = L
    new XorTMonadFilter[F, L] { implicit val F = F0; implicit val L = L0 }
  }
  */

 /* TODO delete this when MonadCombine instance is re-enabled */
 implicit def xorTMonoidK[F[_], L](implicit F: Monad[F], L: Monoid[L]): MonoidK[XorT[F, L, ?]] = {
    implicit val F0 = F
    implicit val L0 = L
    new MonoidK[XorT[F, L, ?]] with XorTSemigroupK[F, L] {
      implicit val F = F0; implicit val L = L0
      def empty[A]: XorT[F, L, A] = XorT.left(F.pure(L.empty))(F)
    }
  }
}

private[data] abstract class XorTInstances2 extends XorTInstances3 {
  implicit def xorTMonadError[F[_], L](implicit F: Monad[F]): MonadError[XorT[F, L, ?], L] = {
    implicit val F0 = F
    new XorTMonadError[F, L] { implicit val F = F0 }
  }

  implicit def xorTSemigroupK[F[_], L](implicit F: Monad[F], L: Semigroup[L]): SemigroupK[XorT[F, L, ?]] = {
    implicit val F0 = F
    implicit val L0 = L
    new XorTSemigroupK[F, L] { implicit val F = F0; implicit val L = L0 }
  }
}

private[data] abstract class XorTInstances3 {
  implicit def xorTFunctor[F[_], L](implicit F: Functor[F]): Functor[XorT[F, L, ?]] = {
    implicit val F0 = F
    new XorTFunctor[F, L] { implicit val F = F0 }
  }
}

private[data] trait XorTFunctor[F[_], L] extends Functor[XorT[F, L, ?]] {
  implicit val F: Functor[F]
  override def map[A, B](fa: XorT[F, L, A])(f: A => B): XorT[F, L, B] = fa map f
}

private[data] trait XorTMonadError[F[_], L] extends MonadError[XorT[F, L, ?], L] with XorTFunctor[F, L] {
  implicit val F: Monad[F]
  def pure[A](a: A): XorT[F, L, A] = XorT.pure[F, L, A](a)
  def flatMap[A, B](fa: XorT[F, L, A])(f: A => XorT[F, L, B]): XorT[F, L, B] = fa flatMap f
  def handleErrorWith[A](fea: XorT[F, L, A])(f: L => XorT[F, L, A]): XorT[F, L, A] =
    XorT(F.flatMap(fea.value) {
      case Xor.Left(e) => f(e).value
      case r @ Xor.Right(_) => F.pure(r)
    })
  override def handleError[A](fea: XorT[F, L, A])(f: L => A): XorT[F, L, A] =
    XorT(F.flatMap(fea.value) {
      case Xor.Left(e) => F.pure(Xor.Right(f(e)))
      case r @ Xor.Right(_) => F.pure(r)
    })
  def raiseError[A](e: L): XorT[F, L, A] = XorT.left(F.pure(e))
  override def attempt[A](fla: XorT[F, L, A]): XorT[F, L, L Xor A] = XorT.right(fla.value)
  override def recover[A](fla: XorT[F, L, A])(pf: PartialFunction[L, A]): XorT[F, L, A] =
    fla.recover(pf)
  override def recoverWith[A](fla: XorT[F, L, A])(pf: PartialFunction[L, XorT[F, L, A]]): XorT[F, L, A] =
    fla.recoverWith(pf)
}

private[data] trait XorTSemigroupK[F[_], L] extends SemigroupK[XorT[F, L, ?]] {
  implicit val F: Monad[F]
  implicit val L: Semigroup[L]
  def combine[A](x: XorT[F, L, A], y: XorT[F, L, A]): XorT[F, L, A] =
    XorT(F.flatMap(x.value) {
      case Xor.Left(l1) => F.map(y.value) {
        case Xor.Left(l2) => Xor.Left(L.combine(l1, l2))
        case r @ Xor.Right(_) => r
      }
      case r @ Xor.Right(_) => F.pure[L Xor A](r)
    })
}

private[data] trait XorTMonadFilter[F[_], L] extends MonadFilter[XorT[F, L, ?]] with XorTMonadError[F, L] {
  implicit val F: Monad[F]
  implicit val L: Monoid[L]
  def empty[A]: XorT[F, L, A] = XorT(F.pure(Xor.left(L.empty)))
}

private[data] trait XorTMonadCombine[F[_], L] extends MonadCombine[XorT[F, L, ?]] with XorTMonadFilter[F, L] with XorTSemigroupK[F, L] {
  implicit val F: Monad[F]
  implicit val L: Monoid[L]
}






© 2015 - 2025 Weber Informatics LLC | Privacy Policy