Skip to content

Commit

Permalink
Partial revert of typelevel#1289
Browse files Browse the repository at this point in the history
All APIs that are present in 0.6.x continue to use `Xor`. New additions, notably FlatMapRec stuff, use `Either`.
  • Loading branch information
adelbertc committed Aug 20, 2016
1 parent 6e12494 commit 1867956
Show file tree
Hide file tree
Showing 36 changed files with 155 additions and 142 deletions.
14 changes: 7 additions & 7 deletions core/src/main/scala/cats/ApplicativeError.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package cats

import cats.data.EitherT
import cats.data.{Xor, XorT}
import scala.util.{ Failure, Success, Try }
import scala.util.control.NonFatal

Expand Down Expand Up @@ -37,21 +37,21 @@ trait ApplicativeError[F[_], E] extends Applicative[F] {
def handleError[A](fa: F[A])(f: E => A): F[A] = handleErrorWith(fa)(f andThen pure)

/**
* Handle errors by turning them into [[scala.util.Either]] values.
* Handle errors by turning them into [[cats.data.Xor]] values.
*
* If there is no error, then an `scala.util.Right` value will be returned instead.
*
* All non-fatal errors should be handled by this method.
*/
def attempt[A](fa: F[A]): F[Either[E, A]] = handleErrorWith(
map(fa)(Right(_): Either[E, A])
)(e => pure(Left(e)))
def attempt[A](fa: F[A]): F[Xor[E, A]] = handleErrorWith(
map(fa)(Xor.Right(_): Xor[E, A])
)(e => pure(Xor.Left(e)))

/**
* Similar to [[attempt]], but wraps the result in a [[cats.data.EitherT]] for
* Similar to [[attempt]], but wraps the result in a [[cats.data.XorT]] for
* convenience.
*/
def attemptT[A](fa: F[A]): EitherT[F, E, A] = EitherT(attempt(fa))
def attemptT[A](fa: F[A]): XorT[F, E, A] = XorT(attempt(fa))

/**
* Recover from certain errors by mapping them to an `A` value.
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/scala/cats/Foldable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ import simulacrum.typeclass
/**
* Behaves like traverse_, but uses [[Unapply]] to find the
* [[Applicative]] instance for `G` - used when `G` is a
* type constructor with two or more parameters such as [[scala.util.Either]]
* type constructor with two or more parameters such as `scala.util.Either`
*
* {{{
* scala> import cats.implicits._
Expand Down Expand Up @@ -251,7 +251,7 @@ import simulacrum.typeclass
/**
* Behaves like sequence_, but uses [[Unapply]] to find the
* [[Applicative]] instance for `G` - used when `G` is a
* type constructor with two or more parameters such as [[scala.util.Either]]
* type constructor with two or more parameters such as `scala.util.Either`
*
* {{{
* scala> import cats.implicits._
Expand Down
19 changes: 11 additions & 8 deletions core/src/main/scala/cats/arrow/Choice.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cats
package arrow

import cats.data.Xor
import simulacrum.typeclass

@typeclass trait Choice[F[_, _]] extends Category[F] {
Expand All @@ -11,35 +12,37 @@ import simulacrum.typeclass
*
* Example:
* {{{
* scala> import cats.data.Xor
* scala> import cats.implicits._
* scala> val b: Boolean => String = _ + " is a boolean"
* scala> val i: Int => String = _ + " is an integer"
* scala> val f: (Either[Boolean, Int]) => String = Choice[Function1].choice(b, i)
* scala> val f: Xor[Boolean, Int] => String = Choice[Function1].choice(b, i)
*
* scala> f(Right(3))
* scala> f(Xor.Right(3))
* res0: String = 3 is an integer
*
* scala> f(Left(false))
* scala> f(Xor.Left(false))
* res0: String = false is a boolean
* }}}
*/
def choice[A, B, C](f: F[A, C], g: F[B, C]): F[Either[A, B], C]
def choice[A, B, C](f: F[A, C], g: F[B, C]): F[Xor[A, B], C]

/**
* An `F` that, given a source `A` on either the right or left side, will
* return that same `A` object.
*
* Example:
* {{{
* scala> import cats.data.Xor
* scala> import cats.implicits._
* scala> val f: (Either[Int, Int]) => Int = Choice[Function1].codiagonal[Int]
* scala> val f: (Xor[Int, Int]) => Int = Choice[Function1].codiagonal[Int]
*
* scala> f(Right(3))
* scala> f(Xor.Right(3))
* res0: Int = 3
*
* scala> f(Left(3))
* scala> f(Xor.Left(3))
* res1: Int = 3
* }}}
*/
def codiagonal[A]: F[Either[A, A], A] = choice(id, id)
def codiagonal[A]: F[Xor[A, A], A] = choice(id, id)
}
6 changes: 3 additions & 3 deletions core/src/main/scala/cats/arrow/FunctionK.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package cats
package arrow

import cats.data. Coproduct
import cats.data.{Coproduct, Xor}

trait FunctionK[F[_], G[_]] extends Serializable { self =>
def apply[A](fa: F[A]): G[A]
Expand All @@ -17,8 +17,8 @@ trait FunctionK[F[_], G[_]] extends Serializable { self =>
def or[H[_]](h: FunctionK[H, G]): FunctionK[Coproduct[F, H, ?], G] =
new FunctionK[Coproduct[F, H, ?], G] {
def apply[A](fa: Coproduct[F, H, A]): G[A] = fa.run match {
case Left(ff) => self(ff)
case Right(gg) => h(gg)
case Xor.Left(ff) => self(ff)
case Xor.Right(gg) => h(gg)
}
}
}
Expand Down
17 changes: 8 additions & 9 deletions core/src/main/scala/cats/data/Coproduct.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@ package data

import cats.arrow.FunctionK
import cats.functor.Contravariant
import cats.syntax.either._

/** `F` on the left and `G` on the right of [[scala.util.Either]].
/** `F` on the left and `G` on the right of [[cats.data.Xor]].
*
* @param run The underlying [[scala.util.Either]].
* @param run The underlying [[cats.data.Xor]].
*/
final case class Coproduct[F[_], G[_], A](run: Either[F[A], G[A]]) {
final case class Coproduct[F[_], G[_], A](run: Xor[F[A], G[A]]) {

import Coproduct._

Expand Down Expand Up @@ -87,17 +86,17 @@ final case class Coproduct[F[_], G[_], A](run: Either[F[A], G[A]]) {
object Coproduct extends CoproductInstances {

def leftc[F[_], G[_], A](x: F[A]): Coproduct[F, G, A] =
Coproduct(Left(x))
Coproduct(Xor.Left(x))

def rightc[F[_], G[_], A](x: G[A]): Coproduct[F, G, A] =
Coproduct(Right(x))
Coproduct(Xor.Right(x))

final class CoproductLeft[G[_]] private[Coproduct] {
def apply[F[_], A](fa: F[A]): Coproduct[F, G, A] = Coproduct(Left(fa))
def apply[F[_], A](fa: F[A]): Coproduct[F, G, A] = Coproduct(Xor.Left(fa))
}

final class CoproductRight[F[_]] private[Coproduct] {
def apply[G[_], A](ga: G[A]): Coproduct[F, G, A] = Coproduct(Right(ga))
def apply[G[_], A](ga: G[A]): Coproduct[F, G, A] = Coproduct(Xor.Right(ga))
}

def left[G[_]]: CoproductLeft[G] = new CoproductLeft[G]
Expand All @@ -107,7 +106,7 @@ object Coproduct extends CoproductInstances {

private[data] sealed abstract class CoproductInstances3 {

implicit def catsDataEqForCoproduct[F[_], G[_], A](implicit E: Eq[Either[F[A], G[A]]]): Eq[Coproduct[F, G, A]] =
implicit def catsDataEqForCoproduct[F[_], G[_], A](implicit E: Eq[Xor[F[A], G[A]]]): Eq[Coproduct[F, G, A]] =
Eq.by(_.run)

implicit def catsDataFunctorForCoproduct[F[_], G[_]](implicit F0: Functor[F], G0: Functor[G]): Functor[Coproduct[F, G, ?]] =
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/scala/cats/data/EitherT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ private[data] trait EitherTMonadError[F[_], L] extends MonadError[EitherT[F, L,
case r @ Right(_) => F.pure(r)
})
def raiseError[A](e: L): EitherT[F, L, A] = EitherT.left(F.pure(e))
override def attempt[A](fla: EitherT[F, L, A]): EitherT[F, L, Either[L, A]] = EitherT.right(fla.value)
override def attempt[A](fla: EitherT[F, L, A]): EitherT[F, L, Xor[L, A]] = EitherT.right(F.map(fla.value)(_.toXor))
override def recover[A](fla: EitherT[F, L, A])(pf: PartialFunction[L, A]): EitherT[F, L, A] =
fla.recover(pf)
override def recoverWith[A](fla: EitherT[F, L, A])(pf: PartialFunction[L, EitherT[F, L, A]]): EitherT[F, L, A] =
Expand Down
12 changes: 6 additions & 6 deletions core/src/main/scala/cats/data/Ior.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ import scala.annotation.tailrec
* - `[[Ior.Right Right]][B]`
* - `[[Ior.Both Both]][A, B]`
*
* `A [[Ior]] B` is similar to `Either[A, B]`, except that it can represent the simultaneous presence of
* `A [[Ior]] B` is similar to `Xor[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]].
* `[[Semigroup]][A]`, while other methods, like [[toXor]], 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`
* `A [[Ior]] B` is isomorphic to `Xor[Xor[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.
* The isomorphic [[cats.data.Xor]] form can be accessed via the [[unwrap]] method.
*/
sealed abstract class Ior[+A, +B] extends Product with Serializable {

Expand All @@ -36,10 +36,10 @@ sealed abstract class Ior[+A, +B] extends Product with Serializable {
final def right: Option[B] = fold(_ => None, b => Some(b), (_, b) => Some(b))
final def onlyLeft: Option[A] = fold(a => Some(a), _ => None, (_, _) => None)
final def onlyRight: Option[B] = fold(_ => None, b => Some(b), (_, _) => None)
final def onlyLeftOrRight: Option[Either[A, B]] = fold(a => Some(Left(a)), b => Some(Right(b)), (_, _) => None)
final def onlyLeftOrRight: Option[Xor[A, B]] = fold(a => Some(Xor.Left(a)), b => Some(Xor.Right(b)), (_, _) => None)
final def onlyBoth: Option[(A, B)] = fold(_ => None, _ => None, (a, b) => Some((a, b)))
final def pad: (Option[A], Option[B]) = fold(a => (Some(a), None), b => (None, Some(b)), (a, b) => (Some(a), Some(b)))
final def unwrap: Either[Either[A, B], (A, B)] = fold(a => Left(Left(a)), b => Left(Right(b)), (a, b) => Right((a, b)))
final def unwrap: Xor[Xor[A, B], (A, B)] = fold(a => Xor.Left(Xor.Left(a)), b => Xor.Left(Xor.Right(b)), (a, b) => Xor.Right((a, b)))

final def toXor: A Xor B = fold(Xor.left, Xor.right, (_, b) => Xor.right(b))
final def toEither: Either[A, B] = fold(Left(_), Right(_), (_, b) => Right(b))
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/scala/cats/data/Kleisli.scala
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ private[data] sealed abstract class KleisliInstances extends KleisliInstances0 {
new Choice[Kleisli[F, ?, ?]] {
def id[A]: Kleisli[F, A, A] = Kleisli(ev.pure(_))

def choice[A, B, C](f: Kleisli[F, A, C], g: Kleisli[F, B, C]): Kleisli[F, Either[A, B], C] =
def choice[A, B, C](f: Kleisli[F, A, C], g: Kleisli[F, B, C]): Kleisli[F, Xor[A, B], C] =
Kleisli(_.fold(f.run, g.run))

def compose[A, B, C](f: Kleisli[F, B, C], g: Kleisli[F, A, B]): Kleisli[F, A, C] =
Expand Down
8 changes: 4 additions & 4 deletions core/src/main/scala/cats/data/OptionT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,11 @@ final case class OptionT[F[_], A](value: F[Option[A]]) {
case None => default
})

def toRight[L](left: => L)(implicit F: Functor[F]): EitherT[F, L, A] =
EitherT(cata(Left(left), Right.apply))
def toRight[L](left: => L)(implicit F: Functor[F]): XorT[F, L, A] =
XorT(cata(Xor.Left(left), Xor.Right.apply))

def toLeft[R](right: => R)(implicit F: Functor[F]): EitherT[F, A, R] =
EitherT(cata(Right(right), Left.apply))
def toLeft[R](right: => R)(implicit F: Functor[F]): XorT[F, A, R] =
XorT(cata(Xor.Right(right), Xor.Left.apply))

def show(implicit F: Show[F[Option[A]]]): String = F.show(value)

Expand Down
13 changes: 9 additions & 4 deletions core/src/main/scala/cats/data/Validated.scala
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,11 @@ sealed abstract class Validated[+E, +A] extends Product with Serializable {
def toXor: Xor[E, A] = fold(Xor.Left.apply, Xor.Right.apply)

/**
* Convert to an Either, apply a function, convert back. This is handy
* when you want to use the Monadic properties of the Either type.
* Convert to an Xor, apply a function, convert back. This is handy
* when you want to use the Monadic properties of the Xor type.
*/
def withEither[EE, B](f: Either[E, A] => Either[EE, B]): Validated[EE, B] =
Validated.fromEither(f(toEither))
def withXor[EE, B](f: Xor[E, A] => Xor[EE, B]): Validated[EE, B] =
Validated.fromXor(f(toXor))

/**
* Validated is a [[functor.Bifunctor]], this method applies one of the
Expand Down Expand Up @@ -391,6 +391,11 @@ trait ValidatedFunctions {
*/
def fromEither[A, B](e: Either[A, B]): Validated[A, B] = e.fold(invalid, valid)

/**
* Converts an `Xor[A, B]` to an `Validated[A, B]`.
*/
def fromXor[A, B](e: Xor[A, B]): Validated[A, B] = e.fold(invalid, valid)

/**
* Converts an `Option[B]` to an `Validated[A, B]`, where the provided `ifNone` values is returned on
* the invalid of the `Validated` when the specified `Option` is `None`.
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/scala/cats/data/Xor.scala
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ private[data] sealed abstract class XorInstances extends XorInstances1 {
override def map[B, C](fa: A Xor B)(f: B => C): A Xor C = fa.map(f)
override def map2Eval[B, C, Z](fb: A Xor B, fc: Eval[A Xor C])(f: (B, C) => Z): Eval[A Xor Z] =
fb.map2Eval(fc)(f)
override def attempt[B](fab: A Xor B): A Xor (Either[A, B]) = Xor.right(fab.toEither)
override def attempt[B](fab: A Xor B): A Xor (Xor[A, B]) = Xor.right(fab)
override def recover[B](fab: A Xor B)(pf: PartialFunction[A, B]): A Xor B =
fab recover pf
override def recoverWith[B](fab: A Xor B)(pf: PartialFunction[A, A Xor B]): A Xor B =
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/scala/cats/data/XorT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,7 @@ private[data] trait XorTMonadError[F[_], L] extends MonadError[XorT[F, L, ?], L]
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, Either[L, A]] = XorT.right(fla.toEither)
override def attempt[A](fla: XorT[F, L, A]): XorT[F, L, Xor[L, 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] =
Expand Down
3 changes: 2 additions & 1 deletion core/src/main/scala/cats/instances/either.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cats
package instances

import cats.data.Xor
import cats.syntax.EitherUtil
import cats.syntax.either._
import scala.annotation.tailrec
Expand Down Expand Up @@ -71,7 +72,7 @@ trait EitherInstances extends EitherInstances1 {
def foldRight[B, C](fa: Either[A, B], lc: Eval[C])(f: (B, Eval[C]) => Eval[C]): Eval[C] =
fa.fold(_ => lc, b => f(b, lc))

override def attempt[B](fab: Either[A, B]): Either[A, Either[A, B]] = Right(fab)
override def attempt[B](fab: Either[A, B]): Either[A, Xor[A, B]] = Right(fab.toXor)
override def recover[B](fab: Either[A, B])(pf: PartialFunction[A, B]): Either[A, B] =
fab recover pf
override def recoverWith[B](fab: Either[A, B])(pf: PartialFunction[A, Either[A, B]]): Either[A, B] =
Expand Down
7 changes: 4 additions & 3 deletions core/src/main/scala/cats/instances/function.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cats
package instances

import cats.arrow.{Arrow, Choice}
import cats.data.Xor
import cats.functor.Contravariant
import annotation.tailrec

Expand Down Expand Up @@ -70,10 +71,10 @@ private[instances] sealed trait Function1Instances extends Function1Instances0 {

implicit val catsStdInstancesForFunction1: Choice[Function1] with Arrow[Function1] =
new Choice[Function1] with Arrow[Function1] {
def choice[A, B, C](f: A => C, g: B => C): Either[A, B] => C =
def choice[A, B, C](f: A => C, g: B => C): Xor[A, B] => C =
_ match {
case Left(a) => f(a)
case Right(b) => g(b)
case Xor.Left(a) => f(a)
case Xor.Right(b) => g(b)
}

def lift[A, B](f: A => B): A => B = f
Expand Down
5 changes: 3 additions & 2 deletions core/src/main/scala/cats/instances/future.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cats
package instances

import cats.data.Xor
import scala.util.control.NonFatal
import scala.concurrent.{ExecutionContext, Future}

Expand All @@ -27,8 +28,8 @@ trait FutureInstances extends FutureInstances1 {
def raiseError[A](e: Throwable): Future[A] = Future.failed(e)
override def handleError[A](fea: Future[A])(f: Throwable => A): Future[A] = fea.recover { case t => f(t) }

override def attempt[A](fa: Future[A]): Future[Either[Throwable, A]] =
(fa.map(a => Right[Throwable, A](a))) recover { case NonFatal(t) => Left(t) }
override def attempt[A](fa: Future[A]): Future[Xor[Throwable, A]] =
(fa.map(a => Xor.Right(a))) recover { case NonFatal(t) => Xor.Left(t) }

override def recover[A](fa: Future[A])(pf: PartialFunction[Throwable, A]): Future[A] = fa.recover(pf)

Expand Down
5 changes: 3 additions & 2 deletions core/src/main/scala/cats/instances/try.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package instances

import TryInstances.castFailure

import cats.data.Xor
import scala.util.control.NonFatal
import scala.util.{Failure, Success, Try}
import scala.annotation.tailrec
Expand Down Expand Up @@ -66,8 +67,8 @@ trait TryInstances extends TryInstances1 {
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.map(a => Right[Throwable, A](a))) recover { case NonFatal(t) => Left(t) }
override def attempt[A](ta: Try[A]): Try[Xor[Throwable, A]] =
(ta.map(a => Xor.Right(a))) recover { case NonFatal(t) => Xor.Left(t) }

override def recover[A](ta: Try[A])(pf: PartialFunction[Throwable, A]): Try[A] =
ta.recover(pf)
Expand Down
6 changes: 3 additions & 3 deletions core/src/main/scala/cats/syntax/applicativeError.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package cats
package syntax

import cats.data.EitherT
import cats.data.{Xor, XorT}

trait ApplicativeErrorSyntax {
implicit def catsSyntaxApplicativeErrorId[E](e: E): ApplicativeErrorIdOps[E] =
Expand All @@ -24,10 +24,10 @@ final class ApplicativeErrorOps[F[_], E, A](fa: F[A])(implicit F: ApplicativeErr
def handleErrorWith(f: E => F[A]): F[A] =
F.handleErrorWith(fa)(f)

def attempt: F[Either[E, A]] =
def attempt: F[Xor[E, A]] =
F.attempt(fa)

def attemptT: EitherT[F, E, A] =
def attemptT: XorT[F, E, A] =
F.attemptT(fa)

def recover(pf: PartialFunction[E, A]): F[A] =
Expand Down
Loading

0 comments on commit 1867956

Please sign in to comment.