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

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

The newest version!
package cats
package data

import cats.Bifunctor
import cats.arrow.FunctionK
import cats.data.Validated.{Invalid, Valid}

import scala.annotation.tailrec

/** Represents a right-biased disjunction that is either an `A`, or a `B`, or both an `A` and a `B`.
 *
 * An instance of `A [[Ior]] B` is one of:
 *  - `[[Ior.Left Left]][A]`
 *  - `[[Ior.Right Right]][B]`
 *  - `[[Ior.Both Both]][A, B]`
 *
 * `A [[Ior]] B` is similar to `scala.util.Either[A, B]`, except that it can represent the simultaneous presence of
 * an `A` and a `B`. It is right-biased so methods such as `map` and `flatMap` operate on the
 * `B` value. Some methods, like `flatMap`, handle the presence of two [[Ior.Both Both]] values using a
 * `[[Semigroup]][A]`, while other methods, like [[toEither]], ignore the `A` value in a [[Ior.Both Both]].
 *
 * `A [[Ior]] B` is isomorphic to `Either[Either[A, B], (A, B)]`, but provides methods biased toward `B`
 * values, regardless of whether the `B` values appear in a [[Ior.Right Right]] or a [[Ior.Both Both]].
 * The isomorphic `scala.util.Either` form can be accessed via the [[unwrap]] method.
 */
sealed abstract class Ior[+A, +B] extends Product with Serializable {

  /**
   * Example:
   * {{{
   * scala> import cats.data.Ior
   * scala> import cats.implicits._
   *
   * scala> val rightF: Int => String = _.show
   * scala> val bothF: (String,Int) => String = (a,b) => a.combine(b.show)
   *
   * scala> val ior1 = "abc".leftIor[Int]
   * scala> ior1.fold(identity, rightF, bothF)
   * res0: String = abc
   *
   * scala> val ior2 = 123.rightIor[String]
   * scala> ior2.fold(identity, rightF, bothF)
   * res1: String = 123
   *
   * scala> val ior3 = Ior.Both("abc", 123)
   * scala> ior3.fold(identity, rightF, bothF)
   * res2: String = abc123
   * }}}
   */
  final def fold[C](fa: A => C, fb: B => C, fab: (A, B) => C): C = this match {
    case Ior.Left(a)    => fa(a)
    case Ior.Right(b)   => fb(b)
    case Ior.Both(a, b) => fab(a, b)
  }

  /**
   * Example:
   * {{{
   * scala> import cats.data.Ior
   * scala> import cats.implicits._
   *
   * scala> val ior1 = "abc".leftIor[Int]
   * scala> ior1.putLeft(true)
   * res0: Ior[Boolean, Int] = Left(true)
   *
   * scala> val ior2 = 123.rightIor[String]
   * scala> ior2.putLeft(false)
   * res1: Ior[Boolean, Int] = Both(false,123)
   *
   * scala> val ior3 = Ior.Both("abc",123)
   * scala> ior3.putLeft(true)
   * res2: Ior[Boolean, Int] = Both(true,123)
   * }}}
   */
  final def putLeft[C](left: C): C Ior B =
    fold(_ => Ior.left(left), Ior.both(left, _), (_, b) => Ior.both(left, b))

  /**
   * Example:
   * {{{
   * scala> import cats.data.Ior
   * scala> import cats.implicits._
   *
   * scala> val ior1 = "abc".leftIor[Int]
   * scala> ior1.putRight(123L)
   * res0: Ior[String, Long] = Both(abc,123)
   *
   * scala> val ior2 = 123.rightIor[String]
   * scala> ior2.putRight(123L)
   * res1: Ior[String, Long] = Right(123)
   *
   * scala> val ior3 = Ior.Both("abc",123)
   * scala> ior3.putRight(123L)
   * res2: Ior[String, Long] = Both(abc,123)
   * }}}
   */
  final def putRight[C](right: C): A Ior C =
    fold(Ior.both(_, right), _ => Ior.right(right), (a, _) => Ior.both(a, right))

  /**
   * Example:
   * {{{
   * scala> import cats.data.Ior
   * scala> import cats.implicits._
   *
   * scala> "abc".leftIor[Int].isLeft
   * res0: Boolean = true
   *
   * scala> 123.rightIor[String].isLeft
   * res1: Boolean = false
   *
   * scala> Ior.Both("abc", 123).isLeft
   * res2: Boolean = false
   * }}}
   */
  final def isLeft: Boolean = fold(_ => true, _ => false, (_, _) => false)
  final def isRight: Boolean = fold(_ => false, _ => true, (_, _) => false)
  final def isBoth: Boolean = fold(_ => false, _ => false, (_, _) => true)

  /**
   * Example:
   * {{{
   * scala> import cats.data.Ior
   * scala> import cats.implicits._
   *
   * scala> "abc".leftIor[Int].left
   * res0: Option[String] = Some(abc)
   *
   * scala> 123.rightIor[String].left
   * res1: Option[String] = None
   *
   * scala> Ior.Both("abc", 123).left
   * res2: Option[String] = Some(abc)
   * }}}
   */
  final def left: Option[A] = fold(a => Some(a), _ => None, (a, _) => Some(a))

  /**
   * Example:
   * {{{
   * scala> import cats.data.Ior
   * scala> import cats.implicits._
   *
   * scala> "abc".leftIor[Int].right
   * res0: Option[Int] = None
   *
   * scala> 123.rightIor[String].right
   * res1: Option[Int] = Some(123)
   *
   * scala> Ior.Both("abc", 123).right
   * res2: Option[Int] = Some(123)
   * }}}
   */
  final def right: Option[B] = fold(_ => None, b => Some(b), (_, b) => Some(b))

  /**
   * Example:
   * {{{
   * scala> import cats.data.Ior
   * scala> import cats.implicits._
   *
   * scala> "abc".leftIor[Int].onlyLeft
   * res0: Option[String] = Some(abc)
   *
   * scala> 123.rightIor[String].onlyLeft
   * res1: Option[String] = None
   *
   * scala> Ior.Both("abc", 123).onlyLeft
   * res2: Option[String] = None
   * }}}
   */
  final def onlyLeft: Option[A] = fold(a => Some(a), _ => None, (_, _) => None)

  /**
   * Example:
   * {{{
   * scala> import cats.data.Ior
   * scala> import cats.implicits._
   *
   * scala> "abc".leftIor[Int].onlyRight
   * res0: Option[Int] = None
   *
   * scala> 123.rightIor[String].onlyRight
   * res1: Option[Int] = Some(123)
   *
   * scala> Ior.Both("abc", 123).onlyRight
   * res2: Option[Int] = None
   * }}}
   */
  final def onlyRight: Option[B] = fold(_ => None, b => Some(b), (_, _) => None)

  /**
   * Example:
   * {{{
   * scala> import cats.data.Ior
   * scala> import cats.implicits._
   *
   * scala> "abc".leftIor[Int].onlyLeftOrRight
   * res0: Option[Either[String, Int]] = Some(Left(abc))
   *
   * scala> 123.rightIor[String].onlyLeftOrRight
   * res1: Option[Either[String, Int]] = Some(Right(123))
   *
   * scala> Ior.Both("abc", 123).onlyLeftOrRight
   * res2: Option[Either[String, Int]] = None
   * }}}
   */
  final def onlyLeftOrRight: Option[Either[A, B]] = fold(a => Some(Left(a)), b => Some(Right(b)), (_, _) => None)

  /**
   * Example:
   * {{{
   * scala> import cats.data.Ior
   * scala> import cats.implicits._
   *
   * scala> "abc".leftIor[Int].onlyBoth
   * res0: Option[(String, Int)] = None
   *
   * scala> 123.rightIor[String].onlyBoth
   * res1: Option[(String, Int)] = None
   *
   * scala> Ior.Both("abc", 123).onlyBoth
   * res2: Option[(String, Int)] = Some((abc,123))
   * }}}
   */
  final def onlyBoth: Option[(A, B)] = fold(_ => None, _ => None, (a, b) => Some((a, b)))

  /**
   * Example:
   * {{{
   * scala> import cats.data.Ior
   * scala> import cats.implicits._
   *
   * scala> "abc".leftIor[Int].pad
   * res0: (Option[String], Option[Int]) = (Some(abc),None)
   *
   * scala> 123.rightIor[String].pad
   * res1: (Option[String], Option[Int]) = (None,Some(123))
   *
   * scala> Ior.Both("abc", 123).pad
   * res2: (Option[String], Option[Int]) = (Some(abc),Some(123))
   * }}}
   */
  final def pad: (Option[A], Option[B]) = fold(a => (Some(a), None), b => (None, Some(b)), (a, b) => (Some(a), Some(b)))

  /**
   * Example:
   * {{{
   * scala> import cats.data.Ior
   * scala> import cats.implicits._
   *
   * scala> "abc".leftIor[Int].unwrap
   * res0: Either[Either[String, Int], (String, Int)] = Left(Left(abc))
   *
   * scala> 123.rightIor[String].unwrap
   * res1: Either[Either[String, Int], (String, Int)] = Left(Right(123))
   *
   * scala> Ior.Both("abc", 123).unwrap
   * res2: Either[Either[String, Int], (String, Int)] = Right((abc,123))
   * }}}
   */
  final def unwrap: Either[Either[A, B], (A, B)] =
    fold(a => Left(Left(a)), b => Left(Right(b)), (a, b) => Right((a, b)))

  /**
   * Example:
   * {{{
   * scala> import cats.data.Ior
   * scala> import cats.implicits._
   *
   * scala> "abc".leftIor[Int].toIorNes
   * res0: IorNes[String, Int] = Left(TreeSet(abc))
   *
   * scala> 123.rightIor[String].toIorNes
   * res1: IorNes[String, Int]= Right(123)
   *
   * scala> Ior.Both("abc", 123).toIorNes
   * res2: IorNes[String, Int] = Both(TreeSet(abc),123)
   * }}}
   */
  final def toIorNes[AA >: A](implicit O: Order[AA]): IorNes[AA, B] = leftMap(NonEmptySet.one(_))

  final def toIorNec[AA >: A]: IorNec[AA, B] = leftMap(NonEmptyChain.one)

  /**
   * Example:
   * {{{
   * scala> import cats.data.Ior
   * scala> import cats.implicits._
   *
   * scala> "abc".leftIor[Int].toIorNel
   * res0: IorNel[String, Int] = Left(NonEmptyList(abc))
   *
   * scala> 123.rightIor[String].toIorNel
   * res1: IorNel[String, Int]= Right(123)
   *
   * scala> Ior.Both("abc", 123).toIorNel
   * res2: IorNel[String, Int] = Both(NonEmptyList(abc),123)
   * }}}
   */
  final def toIorNel[AA >: A]: IorNel[AA, B] = leftMap(NonEmptyList.one)

  /**
   * Example:
   * {{{
   * scala> import cats.data.Ior
   * scala> import cats.implicits._
   *
   * scala> "abc".leftIor[Int].toEither
   * res0: Either[String, Int] = Left(abc)
   *
   * scala> 123.rightIor[String].toEither
   * res1: Either[String, Int]= Right(123)
   *
   * scala> Ior.Both("abc", 123).toEither
   * res2: Either[String, Int] = Right(123)
   * }}}
   */
  final def toEither: Either[A, B] = fold(Left(_), Right(_), (_, b) => Right(b))

  /**
   * Example:
   * {{{
   * scala> import cats.data.Ior
   * scala> import cats.implicits._
   *
   * scala> "abc".leftIor[Int].toValidated
   * res0: Validated[String, Int] = Invalid(abc)
   *
   * scala> 123.rightIor[String].toValidated
   * res1: Validated[String, Int]= Valid(123)
   *
   * scala> Ior.Both("abc", 123).toValidated
   * res2: Validated[String, Int] = Valid(123)
   * }}}
   */
  final def toValidated: Validated[A, B] = fold(Invalid(_), Valid(_), (_, b) => Valid(b))

  /**
   * Example:
   * {{{
   * scala> import cats.data.Ior
   * scala> import cats.implicits._
   *
   * scala> "abc".leftIor[Int].toOption
   * res0: Option[Int] = None
   *
   * scala> 123.rightIor[String].toOption
   * res1: Option[Int]= Some(123)
   *
   * scala> Ior.Both("abc", 123).toOption
   * res2: Option[Int] = Some(123)
   * }}}
   */
  final def toOption: Option[B] = right

  /**
   * Example:
   * {{{
   * scala> import cats.data.Ior
   * scala> import cats.implicits._
   *
   * scala> "abc".leftIor[Int].toList
   * res0: List[Int] = List()
   *
   * scala> 123.rightIor[String].toList
   * res1: List[Int]= List(123)
   *
   * scala> Ior.Both("abc", 123).toList
   * res2: List[Int] = List(123)
   * }}}
   */
  final def toList: List[B] = right.toList

  /**
   * Example:
   * {{{
   * scala> import cats.data.Ior
   * scala> import cats.implicits._
   *
   * scala> "abc".leftIor[Int].to[List, Int]
   * res0: List[Int] = List()
   *
   * scala> 123.rightIor[String].to[List, Int]
   * res1: List[Int]= List(123)
   *
   * scala> Ior.Both("abc", 123).to[List, Int]
   * res2: List[Int] = List(123)
   * }}}
   */
  final def to[F[_], BB >: B](implicit F: Alternative[F]): F[BB] =
    fold(_ => F.empty, F.pure, (_, b) => F.pure(b))

  /**
   * Example:
   * {{{
   * scala> import cats.data.Ior
   * scala> import cats.implicits._
   *
   * scala> "abc".leftIor[Int].swap
   * res0: Ior[Int, String] = Right(abc)
   *
   * scala> 123.rightIor[String].swap
   * res1: Ior[Int, String] = Left(123)
   *
   * scala> Ior.Both("abc", 123).swap
   * res2: Ior[Int, String] = Both(123,abc)
   * }}}
   */
  final def swap: B Ior A = fold(Ior.right, Ior.left, (a, b) => Ior.both(b, a))

  /**
   * Example:
   * {{{
   * scala> import cats.data.Ior
   * scala> import cats.implicits._
   *
   * scala> "abc".leftIor[Int].exists(_ > 100)
   * res0: Boolean = false
   *
   * scala> 123.rightIor[String].exists(_ > 100)
   * res1: Boolean = true
   *
   * scala> Ior.Both("abc", 123).exists(_ > 100)
   * res2: Boolean = true
   * }}}
   */
  final def exists(p: B => Boolean): Boolean = right.exists(p)

  /**
   * Example:
   * {{{
   * scala> import cats.data.Ior
   * scala> import cats.implicits._
   *
   * scala> "abc".leftIor[Int].forall(_ > 100)
   * res0: Boolean = true
   *
   * scala> 123.rightIor[String].forall(_ > 150)
   * res1: Boolean = false
   *
   * scala> Ior.Both("abc", 123).forall(_ > 100)
   * res2: Boolean = true
   * }}}
   */
  final def forall(p: B => Boolean): Boolean = right.forall(p)

  /**
   * Example:
   * {{{
   * scala> import cats.data.Ior
   * scala> import cats.implicits._
   *
   * scala> "abc".leftIor[Int].getOrElse(456)
   * res0: Int = 456
   *
   * scala> 123.rightIor[String].getOrElse(456)
   * res1: Int = 123
   *
   * scala> Ior.Both("abc", 123).getOrElse(456)
   * res2: Int = 123
   * }}}
   */
  final def getOrElse[BB >: B](bb: => BB): BB = right.getOrElse(bb)

  /**
   * Example:
   * {{{
   * scala> import cats.data.Ior
   * scala> import cats.implicits._
   *
   * scala> "abc".leftIor[Int].valueOr(_.length)
   * res0: Int = 3
   *
   * scala> 123.rightIor[String].valueOr(_.length)
   * res1: Int = 123
   *
   * scala> Ior.Both("abc", 123).valueOr(_.length)
   * res2: Int = 126
   * }}}
   */
  final def valueOr[BB >: B](f: A => BB)(implicit BB: Semigroup[BB]): BB =
    fold(f, identity, (a, b) => BB.combine(f(a), b))

  /**
   * Example:
   * {{{
   * scala> import cats.data.Ior
   * scala> import cats.implicits._
   *
   * scala> "abc".leftIor[Int].bimap(_.length, identity)
   * res0: Ior[Int, Int] = Left(3)
   *
   * scala> 123.rightIor[String].bimap(_.length, identity)
   * res1: Ior[Int, Int] = Right(123)
   *
   * scala> Ior.Both("abc", 123).bimap(_.length, identity)
   * res2: Ior[Int, Int] = Both(3,123)
   * }}}
   */
  final def bimap[C, D](fa: A => C, fb: B => D): C Ior D =
    fold(a => Ior.left(fa(a)), b => Ior.right(fb(b)), (a, b) => Ior.both(fa(a), fb(b)))

  /**
   * Example:
   * {{{
   * scala> import cats.data.Ior
   * scala> import cats.implicits._
   *
   * scala> "abc".leftIor[Int].bimap(_.length, _ * 2)
   * res0: Ior[Int, Int] = Left(3)
   *
   * scala> 123.rightIor[String].bimap(_.length, _ * 2)
   * res1: Ior[Int, Int] = Right(246)
   *
   * scala> Ior.Both("abc", 123).bimap(_.length, _ * 2)
   * res2: Ior[Int, Int] = Both(3,246)
   * }}}
   */
  final def map[D](f: B => D): A Ior D = bimap(identity, f)

  /**
   * Example:
   * {{{
   * scala> import cats.data.Ior
   * scala> import cats.implicits._
   *
   * scala> "abc".leftIor[Int].leftMap(_.length)
   * res0: Ior[Int, Int] = Left(3)
   *
   * scala> 123.rightIor[String].leftMap(_.length)
   * res1: Ior[Int, Int] = Right(123)
   *
   * scala> Ior.Both("abc", 123).leftMap(_.length)
   * res2: Ior[Int, Int] = Both(3,123)
   * }}}
   */
  final def leftMap[C](f: A => C): C Ior B = bimap(f, identity)

  /**
   * Example:
   * {{{
   * scala> import cats.data.Ior
   * scala> import cats.implicits._
   *
   * scala> "abc".leftIor[Int].flatMap(i => 456.rightIor[String])
   * res0: Ior[String, Int] = Left(abc)
   *
   * scala> 123.rightIor[String].flatMap(i => (i * 2).rightIor[String])
   * res1: Ior[String, Int] = Right(246)
   *
   * scala> 123.rightIor[String].flatMap(_ => "error".leftIor[Int])
   * res2: Ior[String, Int] = Left(error)
   *
   * scala> Ior.Both("abc", 123).flatMap(_ => 456.rightIor[String])
   * res3: Ior[String, Int] = Both(abc,456)
   *
   * scala> Ior.Both("abc", 123).flatMap(_ => "error".leftIor[Int])
   * res4: Ior[String, Int] = Left(abcerror)
   *
   * scala> Ior.Both("abc", 123).flatMap(_ => Ior.Both("error",456))
   * res5: Ior[String, Int] = Both(abcerror,456)
   * }}}
   */
  final def flatMap[AA >: A, D](f: B => AA Ior D)(implicit AA: Semigroup[AA]): AA Ior D = this match {
    case l @ Ior.Left(_) => l
    case Ior.Right(b)    => f(b)
    case Ior.Both(a1, b) =>
      f(b) match {
        case Ior.Left(a2)    => Ior.Left(AA.combine(a1, a2))
        case Ior.Right(b)    => Ior.Both(a1, b)
        case Ior.Both(a2, d) => Ior.Both(AA.combine(a1, a2), d)
      }
  }

  final def foreach(f: B => Unit): Unit = {
    bimap(_ => (), f)
    ()
  }

  final def traverse[F[_], AA >: A, D](g: B => F[D])(implicit F: Applicative[F]): F[AA Ior D] = this match {
    case Ior.Left(a)    => F.pure(Ior.left(a))
    case Ior.Right(b)   => F.map(g(b))(Ior.right)
    case Ior.Both(a, b) => F.map(g(b))(d => Ior.both(a, d))
  }

  /**
   * Example:
   * {{{
   * scala> import cats.data.Ior
   * scala> import cats.implicits._
   *
   * scala> "abc".leftIor[Int].foldLeft(List(456))((c,b) => b :: c)
   * res0: List[Int] = List(456)
   *
   * scala> 123.rightIor[String].foldLeft(List(456))((c,b) => b :: c)
   * res1: List[Int] = List(123, 456)
   *
   * scala> Ior.Both("abc", 123).foldLeft(List(456))((c,b) => b :: c)
   * res2: List[Int] = List(123, 456)
   * }}}
   */
  final def foldLeft[C](c: C)(f: (C, B) => C): C =
    fold(_ => c, f(c, _), (_, b) => f(c, b))

  final def foldRight[C](lc: Eval[C])(f: (B, Eval[C]) => Eval[C]): Eval[C] =
    fold(_ => lc, f(_, lc), (_, b) => f(b, lc))

  final def merge[AA >: A](implicit ev: B <:< AA, AA: Semigroup[AA]): AA =
    fold(identity, ev, (a, b) => AA.combine(a, b))
  final def mergeLeft[AA >: A](implicit ev: B <:< AA): AA =
    fold(identity, ev, (a, _) => a)
  final def mergeRight[AA >: A](implicit ev: B <:< AA): AA =
    fold(identity, ev, (_, b) => ev(b))

  /**
   * Example:
   * {{{
   * scala> import cats.data.Ior
   * scala> import cats.implicits._
   *
   * scala> "abc".leftIor[Int].combine("other".leftIor[Int])
   * res0: Ior[String, Int] = Left(abcother)
   *
   * scala> "abc".leftIor[Int].combine(456.rightIor[String])
   * res1: Ior[String, Int] = Both(abc,456)
   *
   * scala> 123.rightIor[String].combine("other".leftIor[Int])
   * res2: Ior[String, Int] = Both(other,123)
   *
   * scala> Ior.Both("abc", 123).combine(Ior.Both("other",456))
   * res3: Ior[String, Int] = Both(abcother,579)
   *
   * scala> Ior.Both("abc", 123).combine("other".leftIor[Int])
   * res3: Ior[String, Int] = Both(abcother,123)
   *
   * scala> Ior.Both("abc", 123).combine(456.rightIor[String])
   * res3: Ior[String, Int] = Both(abc,579)
   * }}}
   */
  // scalastyle:off cyclomatic.complexity
  final def combine[AA >: A, BB >: B](that: AA Ior BB)(implicit AA: Semigroup[AA], BB: Semigroup[BB]): AA Ior BB =
    this match {
      case Ior.Left(a1) =>
        that match {
          case Ior.Left(a2)     => Ior.Left(AA.combine(a1, a2))
          case Ior.Right(b2)    => Ior.Both(a1, b2)
          case Ior.Both(a2, b2) => Ior.Both(AA.combine(a1, a2), b2)
        }
      case Ior.Right(b1) =>
        that match {
          case Ior.Left(a2)     => Ior.Both(a2, b1)
          case Ior.Right(b2)    => Ior.Right(BB.combine(b1, b2))
          case Ior.Both(a2, b2) => Ior.Both(a2, BB.combine(b1, b2))
        }
      case Ior.Both(a1, b1) =>
        that match {
          case Ior.Left(a2)     => Ior.Both(AA.combine(a1, a2), b1)
          case Ior.Right(b2)    => Ior.Both(a1, BB.combine(b1, b2))
          case Ior.Both(a2, b2) => Ior.Both(AA.combine(a1, a2), BB.combine(b1, b2))
        }
    }
  // scalastyle:on cyclomatic.complexity

  final def ===[AA >: A, BB >: B](that: AA Ior BB)(implicit AA: Eq[AA], BB: Eq[BB]): Boolean = fold(
    a => that.fold(a2 => AA.eqv(a, a2), b2 => false, (a2, b2) => false),
    b => that.fold(a2 => false, b2 => BB.eqv(b, b2), (a2, b2) => false),
    (a, b) => that.fold(a2 => false, b2 => false, (a2, b2) => AA.eqv(a, a2) && BB.eqv(b, b2))
  )

  final def show[AA >: A, BB >: B](implicit AA: Show[AA], BB: Show[BB]): String = fold(
    a => s"Ior.Left(${AA.show(a)})",
    b => s"Ior.Right(${BB.show(b)})",
    (a, b) => s"Ior.Both(${AA.show(a)}, ${BB.show(b)})"
  )
}

object Ior extends IorInstances with IorFunctions with IorFunctions2 {
  final case class Left[+A](a: A) extends (A Ior Nothing)
  final case class Right[+B](b: B) extends (Nothing Ior B)
  final case class Both[+A, +B](a: A, b: B) extends (A Ior B)
}

sealed abstract private[data] class IorInstances extends IorInstances0 {

  implicit val catsBitraverseForIor: Bitraverse[Ior] = new Bitraverse[Ior] {

    def bitraverse[G[_], A, B, C, D](fab: Ior[A, B])(f: A => G[C],
                                                     g: B => G[D])(implicit G: Applicative[G]): G[Ior[C, D]] =
      fab match {
        case Ior.Left(a)    => G.map(f(a))(Ior.Left(_))
        case Ior.Right(b)   => G.map(g(b))(Ior.Right(_))
        case Ior.Both(a, b) => G.map2(f(a), g(b))(Ior.Both(_, _))
      }

    def bifoldLeft[A, B, C](fab: Ior[A, B], c: C)(f: (C, A) => C, g: (C, B) => C): C =
      fab match {
        case Ior.Left(a)    => f(c, a)
        case Ior.Right(b)   => g(c, b)
        case Ior.Both(a, b) => g(f(c, a), b)
      }

    def bifoldRight[A, B, C](fab: Ior[A, B], c: Eval[C])(f: (A, Eval[C]) => Eval[C],
                                                         g: (B, Eval[C]) => Eval[C]): Eval[C] =
      fab match {
        case Ior.Left(a)    => f(a, c)
        case Ior.Right(b)   => g(b, c)
        case Ior.Both(a, b) => g(b, f(a, c))
      }
  }

  implicit def catsDataEqForIor[A: Eq, B: Eq]: Eq[A Ior B] = new Eq[A Ior B] {
    def eqv(x: A Ior B, y: A Ior B): Boolean = x === y
  }

  implicit def catsDataShowForIor[A: Show, B: Show]: Show[A Ior B] = new Show[A Ior B] {
    def show(f: A Ior B): String = f.show
  }

  implicit def catsDataSemigroupForIor[A: Semigroup, B: Semigroup]: Semigroup[Ior[A, B]] = new Semigroup[Ior[A, B]] {
    def combine(x: Ior[A, B], y: Ior[A, B]) = x.combine(y)
  }

  implicit def catsDataMonadErrorForIor[A: Semigroup]: MonadError[Ior[A, *], A] =
    new MonadError[Ior[A, *], A] {

      def raiseError[B](e: A): Ior[A, B] = Ior.left(e)

      def handleErrorWith[B](fa: Ior[A, B])(f: (A) => Ior[A, B]): Ior[A, B] =
        fa match {
          case Ior.Left(e) => f(e)
          case _           => fa
        }

      def flatMap[B, C](fa: Ior[A, B])(f: B => Ior[A, C]): Ior[A, C] = fa.flatMap(f)

      override def map2Eval[B, C, Z](fa: Ior[A, B], fb: Eval[Ior[A, C]])(f: (B, C) => Z): Eval[Ior[A, Z]] =
        fa match {
          case l @ Ior.Left(_) => Eval.now(l) // no need to evaluate fb
          case notLeft         => fb.map(fb => map2(notLeft, fb)(f))
        }

      def tailRecM[B, C](b: B)(fn: B => Ior[A, Either[B, C]]): A Ior C = {
        @tailrec
        def loop(v: Ior[A, Either[B, C]]): A Ior C = v match {
          case Ior.Left(a)           => Ior.left(a)
          case Ior.Right(Right(c))   => Ior.right(c)
          case Ior.Both(a, Right(c)) => Ior.both(a, c)
          case Ior.Right(Left(b))    => loop(fn(b))
          case Ior.Both(a, Left(b)) =>
            fn(b) match {
              case Ior.Left(aa)    => Ior.left(Semigroup[A].combine(a, aa))
              case Ior.Both(aa, x) => loop(Ior.both(Semigroup[A].combine(a, aa), x))
              case Ior.Right(x)    => loop(Ior.both(a, x))
            }
        }
        loop(fn(b))
      }

      override def pure[B](x: B): Ior[A, B] = Ior.right(x)

      override def map[B, C](fa: A Ior B)(f: B => C): A Ior C =
        fa.map(f)
    }

  implicit def catsDataBifunctorForIor: Bifunctor[Ior] =
    new Bifunctor[Ior] {
      override def bimap[A, B, C, D](fab: A Ior B)(f: A => C, g: B => D): C Ior D = fab.bimap(f, g)
    }

  // scalastyle:off cyclomatic.complexity
  implicit def catsDataParallelForIor[E](implicit E: Semigroup[E]): Parallel.Aux[Ior[E, *], Ior[E, *]] =
    new Parallel[Ior[E, *]] {
      type F[x] = Ior[E, x]

      private[this] val identityK: Ior[E, *] ~> Ior[E, *] = FunctionK.id

      def parallel: Ior[E, *] ~> Ior[E, *] = identityK
      def sequential: Ior[E, *] ~> Ior[E, *] = identityK

      val applicative: Applicative[Ior[E, *]] = new Applicative[Ior[E, *]] {
        def pure[A](a: A): Ior[E, A] = Ior.right(a)
        def ap[A, B](ff: Ior[E, A => B])(fa: Ior[E, A]): Ior[E, B] =
          fa match {
            case Ior.Right(a) =>
              ff match {
                case Ior.Right(f)    => Ior.Right(f(a))
                case Ior.Both(e1, f) => Ior.Both(e1, f(a))
                case Ior.Left(e1)    => Ior.Left(e1)
              }
            case Ior.Both(e1, a) =>
              ff match {
                case Ior.Right(f)    => Ior.Both(e1, f(a))
                case Ior.Both(e2, f) => Ior.Both(E.combine(e2, e1), f(a))
                case Ior.Left(e2)    => Ior.Left(E.combine(e2, e1))
              }
            case Ior.Left(e1) =>
              ff match {
                case Ior.Right(f)    => Ior.Left(e1)
                case Ior.Both(e2, f) => Ior.Left(E.combine(e2, e1))
                case Ior.Left(e2)    => Ior.Left(E.combine(e2, e1))
              }
          }
      }

      lazy val monad: Monad[Ior[E, *]] = Monad[Ior[E, *]]
    }
  // scalastyle:on cyclomatic.complexity

}

sealed abstract private[data] class IorInstances0 {

  implicit def catsDataTraverseFunctorForIor[A]: Traverse[Ior[A, *]] = new Traverse[Ior[A, *]] {
    def traverse[F[_]: Applicative, B, C](fa: A Ior B)(f: B => F[C]): F[A Ior C] =
      fa.traverse(f)
    def foldLeft[B, C](fa: A Ior B, b: C)(f: (C, B) => C): C =
      fa.foldLeft(b)(f)
    def foldRight[B, C](fa: A Ior B, lc: Eval[C])(f: (B, Eval[C]) => Eval[C]): Eval[C] =
      fa.foldRight(lc)(f)

    override def size[B](fa: A Ior B): Long = fa.fold(_ => 0L, _ => 1L, (_, _) => 1L)

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

    override def forall[B](fa: Ior[A, B])(p: (B) => Boolean): Boolean = fa.forall(p)

    override def exists[B](fa: Ior[A, B])(p: (B) => Boolean): Boolean = fa.exists(p)

    override def map[B, C](fa: A Ior B)(f: B => C): A Ior C =
      fa.map(f)
  }
}

sealed private[data] trait IorFunctions {
  def left[A, B](a: A): A Ior B = Ior.Left(a)
  def right[A, B](b: B): A Ior B = Ior.Right(b)
  def both[A, B](a: A, b: B): A Ior B = Ior.Both(a, b)
  def leftNel[A, B](a: A): IorNel[A, B] = left(NonEmptyList.one(a))
  def bothNel[A, B](a: A, b: B): IorNel[A, B] = both(NonEmptyList.one(a), b)

  /**
   * Create an `Ior` from two Options if at least one of them is defined.
   *
   * @param oa an element (optional) for the left side of the `Ior`
   * @param ob an element (optional) for the right side of the `Ior`
   *
   * @return `None` if both `oa` and `ob` are `None`. Otherwise `Some` wrapping
   * an [[Ior.Left]], [[Ior.Right]], or [[Ior.Both]] if `oa`, `ob`, or both are
   * defined (respectively).
   *
   * Example:
   * {{{
   * scala> Ior.fromOptions(Option.empty[String], Option.empty[Int])
   * res0: Option[Ior[String, Int]] = None
   * scala> Ior.fromOptions(Option.empty[String], Some(42))
   * res1: Option[Ior[String, Int]] = Some(Right(42))
   * scala> Ior.fromOptions(Some("Error"), Option.empty[Int])
   * res2: Option[Ior[String, Int]] = Some(Left(Error))
   * scala> Ior.fromOptions(Some("Warning"), Some(42))
   * res3: Option[Ior[String, Int]] = Some(Both(Warning,42))
   * }}}
   */
  def fromOptions[A, B](oa: Option[A], ob: Option[B]): Option[A Ior B] =
    oa match {
      case Some(a) =>
        ob match {
          case Some(b) => Some(Ior.Both(a, b))
          case None    => Some(Ior.Left(a))
        }
      case None =>
        ob match {
          case Some(b) => Some(Ior.Right(b))
          case None    => None
        }
    }

  /**
   * Create an `Ior` from an `Either`.
   * @param eab an `Either` from which the `Ior` should be created
   *
   * @return [[Ior.Left]] if the `Either` was a `Left`,
   *         or [[Ior.Right]] if the `Either` was a `Right`
   *
   * Example:
   * {{{
   * scala> Ior.fromEither(Left(1))
   * res0: Ior[Int, Nothing] = Left(1)
   * scala> Ior.fromEither(Right('1'))
   * res1: Ior[Nothing, Char] = Right(1)
   * }}}
   */
  def fromEither[A, B](eab: Either[A, B]): A Ior B =
    eab match {
      case Left(a)  => left(a)
      case Right(b) => right(b)
    }
}

sealed private[data] trait IorFunctions2 {
  def leftNec[A, B](a: A): IorNec[A, B] = Ior.left(NonEmptyChain.one(a))
  def bothNec[A, B](a: A, b: B): IorNec[A, B] = Ior.both(NonEmptyChain.one(a), b)
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy