Skip to content

Commit

Permalink
Merge pull request #1289 from adelbertc/stdlib-eithert
Browse files Browse the repository at this point in the history
Replace Xor with Either, fixes #1192
  • Loading branch information
adelbertc committed Aug 20, 2016
2 parents 61a2a16 + ba1a786 commit 34360f8
Show file tree
Hide file tree
Showing 75 changed files with 1,698 additions and 412 deletions.
16 changes: 8 additions & 8 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.{Xor, XorT}
import cats.data.EitherT
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 [[cats.data.Xor.Left]] values.
* Handle errors by turning them into [[scala.util.Either]] values.
*
* If there is no error, then an [[cats.data.Xor.Right]] value will be returned instead.
* 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[E Xor A] = handleErrorWith(
map(fa)(Xor.right[E, A])
)(e => pure(Xor.left(e)))
def attempt[A](fa: F[A]): F[Either[E, A]] = handleErrorWith(
map(fa)(Right(_): Either[E, A])
)(e => pure(Left(e)))

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

/**
* Recover from certain errors by mapping them to an `A` value.
Expand Down
17 changes: 8 additions & 9 deletions core/src/main/scala/cats/Bitraverse.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,23 @@ import simulacrum.typeclass
*
* Example:
* {{{
* scala> import cats.data.Xor
* scala> import cats.implicits._
*
* scala> val rightSome: Option[String] Xor Option[Int] = Xor.right(Some(3))
* scala> val rightSome: Either[Option[String], Option[Int]] = Either.right(Some(3))
* scala> rightSome.bisequence
* res0: Option[String Xor Int] = Some(Right(3))
* res0: Option[Either[String, Int]] = Some(Right(3))
*
* scala> val rightNone: Option[String] Xor Option[Int] = Xor.right(None)
* scala> val rightNone: Either[Option[String], Option[Int]] = Either.right(None)
* scala> rightNone.bisequence
* res1: Option[String Xor Int] = None
* res1: Option[Either[String, Int]] = None
*
* scala> val leftSome: Option[String] Xor Option[Int] = Xor.left(Some("foo"))
* scala> val leftSome: Either[Option[String], Option[Int]] = Either.left(Some("foo"))
* scala> leftSome.bisequence
* res2: Option[String Xor Int] = Some(Left(foo))
* res2: Option[Either[String, Int]] = Some(Left(foo))
*
* scala> val leftNone: Option[String] Xor Option[Int] = Xor.left(None)
* scala> val leftNone: Either[Option[String], Option[Int]] = Either.left(None)
* scala> leftNone.bisequence
* res3: Option[String Xor Int] = None
* res3: Option[Either[String, Int]] = None
* }}}
*/
def bisequence[G[_]: Applicative, A, B](fab: F[G[A], G[B]]): G[F[A, B]] =
Expand Down
7 changes: 1 addition & 6 deletions core/src/main/scala/cats/Eval.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package cats

import scala.annotation.tailrec
import cats.data.Xor
import cats.syntax.all._

/**
Expand Down Expand Up @@ -302,11 +301,7 @@ private[cats] trait EvalInstances extends EvalInstances0 {
def flatMap[A, B](fa: Eval[A])(f: A => Eval[B]): Eval[B] = fa.flatMap(f)
def extract[A](la: Eval[A]): A = la.value
def coflatMap[A, B](fa: Eval[A])(f: Eval[A] => B): Eval[B] = Later(f(fa))
def tailRecM[A, B](a: A)(f: A => Eval[A Xor B]): Eval[B] =
f(a).flatMap(_ match {
case Xor.Left(a1) => tailRecM(a1)(f) // recursion OK here, since flatMap is lazy
case Xor.Right(b) => Eval.now(b)
})
def tailRecM[A, B](a: A)(f: A => Eval[Either[A, B]]): Eval[B] = defaultTailRecM(a)(f)
}

implicit def catsOrderForEval[A: Order]: Order[Eval[A]] =
Expand Down
5 changes: 2 additions & 3 deletions core/src/main/scala/cats/FlatMap.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package cats

import cats.data.Xor
import simulacrum.typeclass

/**
Expand Down Expand Up @@ -93,7 +92,7 @@ import simulacrum.typeclass
flatMap(fa)(if (_) ifTrue else ifFalse)

/**
* Keeps calling `f` until a `[[cats.data.Xor.Right Right]][B]` is returned.
* Keeps calling `f` until a `scala.util.Right[B]` is returned.
*
* Based on Phil Freeman's
* [[http://functorial.com/stack-safety-for-free/index.pdf Stack Safety for Free]].
Expand All @@ -106,5 +105,5 @@ import simulacrum.typeclass
* using recursive flatMap. Such an implementation will only be stack safe if
* the Monad is trampolined.
*/
def tailRecM[A, B](a: A)(f: A => F[A Xor B]): F[B]
def tailRecM[A, B](a: A)(f: A => F[Either[A, B]]): F[B]
}
27 changes: 12 additions & 15 deletions core/src/main/scala/cats/Foldable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -186,9 +186,8 @@ import simulacrum.typeclass
* For example:
*
* {{{
* scala> import cats.data.Xor
* scala> import cats.implicits._
* scala> def parseInt(s: String): Option[Int] = Xor.catchOnly[NumberFormatException](s.toInt).toOption
* scala> def parseInt(s: String): Option[Int] = Either.catchOnly[NumberFormatException](s.toInt).toOption
* scala> val F = Foldable[List]
* scala> F.traverse_(List("333", "444"))(parseInt)
* res0: Option[Unit] = Some(())
Expand All @@ -208,19 +207,18 @@ 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 [[cats.data.Xor]]
* type constructor with two or more parameters such as [[scala.util.Either]]
*
* {{{
* scala> import cats.data.Xor
* scala> import cats.implicits._
* scala> def parseInt(s: String): Xor[String, Int] =
* | try { Xor.Right(s.toInt) }
* | catch { case _: NumberFormatException => Xor.Left("boo") }
* scala> def parseInt(s: String): Either[String, Int] =
* | try { Right(s.toInt) }
* | catch { case _: NumberFormatException => Left("boo") }
* scala> val F = Foldable[List]
* scala> F.traverseU_(List("333", "444"))(parseInt)
* res0: Xor[String, Unit] = Right(())
* res0: Either[String, Unit] = Right(())
* scala> F.traverseU_(List("333", "zzz"))(parseInt)
* res1: Xor[String, Unit] = Left(boo)
* res1: Either[String, Unit] = Left(boo)
* }}}
*
* Note that using `traverse_` instead of `traverseU_` would not compile without
Expand Down Expand Up @@ -253,16 +251,15 @@ 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 [[cats.data.Xor]]
* type constructor with two or more parameters such as [[scala.util.Either]]
*
* {{{
* scala> import cats.data.Xor
* scala> import cats.implicits._
* scala> val F = Foldable[List]
* scala> F.sequenceU_(List(Xor.right[String, Int](333), Xor.Right(444)))
* res0: Xor[String, Unit] = Right(())
* scala> F.sequenceU_(List(Xor.right[String, Int](333), Xor.Left("boo")))
* res1: Xor[String, Unit] = Left(boo)
* scala> F.sequenceU_(List(Either.right[String, Int](333), Right(444)))
* res0: Either[String, Unit] = Right(())
* scala> F.sequenceU_(List(Either.right[String, Int](333), Left("boo")))
* res1: Either[String, Unit] = Left(boo)
* }}}
*
* Note that using `sequence_` instead of `sequenceU_` would not compile without
Expand Down
7 changes: 3 additions & 4 deletions core/src/main/scala/cats/Monad.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package cats

import cats.data.Xor
import simulacrum.typeclass

/**
Expand All @@ -22,9 +21,9 @@ import simulacrum.typeclass
* to write this method (all cats types have a stack safe version
* of this). When this method is safe you can find an `implicit r: RecursiveTailRecM`.
*/
protected def defaultTailRecM[A, B](a: A)(fn: A => F[A Xor B]): F[B] =
protected def defaultTailRecM[A, B](a: A)(fn: A => F[Either[A, B]]): F[B] =
flatMap(fn(a)) {
case Xor.Right(b) => pure(b)
case Xor.Left(nextA) => defaultTailRecM(nextA)(fn)
case Right(b) => pure(b)
case Left(nextA) => defaultTailRecM(nextA)(fn)
}
}
2 changes: 1 addition & 1 deletion core/src/main/scala/cats/MonadCombine.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import simulacrum.typeclass
* Fold over the inner structure to combine all of the values with
* our combine method inherited from MonoidK. The result is for us
* to accumulate all of the "interesting" values of the inner G, so
* if G is Option, we collect all the Some values, if G is Xor,
* if G is Option, we collect all the Some values, if G is Either,
* we collect all the Right values, etc.
*/
def unite[G[_], A](fga: F[G[A]])(implicit G: Foldable[G]): F[A] =
Expand Down
15 changes: 6 additions & 9 deletions core/src/main/scala/cats/Traverse.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,8 @@ import simulacrum.typeclass
*
* Example:
* {{{
* scala> import cats.data.Xor
* scala> import cats.implicits._
* scala> def parseInt(s: String): Option[Int] = Xor.catchOnly[NumberFormatException](s.toInt).toOption
* scala> def parseInt(s: String): Option[Int] = Either.catchOnly[NumberFormatException](s.toInt).toOption
* scala> List("1", "2", "3").traverse(parseInt)
* res0: Option[List[Int]] = Some(List(1, 2, 3))
* scala> List("1", "two", "3").traverse(parseInt)
Expand All @@ -39,14 +38,13 @@ import simulacrum.typeclass
*
* Example:
* {{{
* scala> import cats.data.Xor
* scala> import cats.implicits._
* scala> def parseInt(s: String): Xor[String, Int] = Xor.catchOnly[NumberFormatException](s.toInt).leftMap(_ => "no number")
* scala> def parseInt(s: String): Either[String, Int] = Either.catchOnly[NumberFormatException](s.toInt).leftMap(_ => "no number")
* scala> val ns = List("1", "2", "3")
* scala> ns.traverseU(parseInt)
* res0: Xor[String, List[Int]] = Right(List(1, 2, 3))
* scala> ns.traverse[Xor[String, ?], Int](parseInt)
* res1: Xor[String, List[Int]] = Right(List(1, 2, 3))
* res0: Either[String, List[Int]] = Right(List(1, 2, 3))
* scala> ns.traverse[Either[String, ?], Int](parseInt)
* res1: Either[String, List[Int]] = Right(List(1, 2, 3))
* }}}
*/
def traverseU[A, GB](fa: F[A])(f: A => GB)(implicit U: Unapply[Applicative, GB]): U.M[F[U.A]] =
Expand All @@ -57,9 +55,8 @@ import simulacrum.typeclass
*
* Example:
* {{{
* scala> import cats.data.Xor
* scala> import cats.implicits._
* scala> def parseInt(s: String): Option[Int] = Xor.catchOnly[NumberFormatException](s.toInt).toOption
* scala> def parseInt(s: String): Option[Int] = Either.catchOnly[NumberFormatException](s.toInt).toOption
* scala> val x = Option(List("1", "two", "3"))
* scala> x.traverseM(_.map(parseInt))
* res0: List[Option[Int]] = List(Some(1), None, Some(3))
Expand Down
21 changes: 8 additions & 13 deletions core/src/main/scala/cats/arrow/Choice.scala
Original file line number Diff line number Diff line change
@@ -1,50 +1,45 @@
package cats
package arrow

import cats.data.Xor

import simulacrum.typeclass

@typeclass trait Choice[F[_, _]] extends Category[F] {

/**
* Given two `F`s (`f` and `g`) with a common target type, create a new `F`
* with the same target type, but with a source type of either `f`'s source
* type OR `g`'s source type.
*
* 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: (Boolean Xor Int) => String = Choice[Function1].choice(b, i)
* scala> val f: (Either[Boolean, Int]) => String = Choice[Function1].choice(b, i)
*
* scala> f(Xor.right(3))
* scala> f(Right(3))
* res0: String = 3 is an integer
*
* scala> f(Xor.left(false))
* scala> f(Left(false))
* res0: String = false is a boolean
* }}}
*/
def choice[A, B, C](f: F[A, C], g: F[B, C]): F[Xor[A, B], C]
def choice[A, B, C](f: F[A, C], g: F[B, C]): F[Either[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: (Int Xor Int) => Int = Choice[Function1].codiagonal[Int]
* scala> val f: (Either[Int, Int]) => Int = Choice[Function1].codiagonal[Int]
*
* scala> f(Xor.right(3))
* scala> f(Right(3))
* res0: Int = 3
*
* scala> f(Xor.left(3))
* scala> f(Left(3))
* res1: Int = 3
* }}}
*/
def codiagonal[A]: F[Xor[A, A], A] = choice(id, id)
def codiagonal[A]: F[Either[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.{Xor, Coproduct}
import cats.data. Coproduct

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 Xor.Left(ff) => self(ff)
case Xor.Right(gg) => h(gg)
case Left(ff) => self(ff)
case Right(gg) => h(gg)
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions core/src/main/scala/cats/data/Cokleisli.scala
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,12 @@ private[data] sealed abstract class CokleisliInstances extends CokleisliInstance
override def map[B, C](fa: Cokleisli[F, A, B])(f: B => C): Cokleisli[F, A, C] =
fa.map(f)

def tailRecM[B, C](b: B)(fn: B => Cokleisli[F, A, B Xor C]): Cokleisli[F, A, C] =
def tailRecM[B, C](b: B)(fn: B => Cokleisli[F, A, Either[B, C]]): Cokleisli[F, A, C] =
Cokleisli({ (fa: F[A]) =>
@tailrec
def loop(c: Cokleisli[F, A, B Xor C]): C = c.run(fa) match {
case Xor.Right(c) => c
case Xor.Left(bb) => loop(fn(bb))
def loop(c: Cokleisli[F, A, Either[B, C]]): C = c.run(fa) match {
case Right(c) => c
case Left(bb) => loop(fn(bb))
}
loop(fn(b))
})
Expand Down
17 changes: 9 additions & 8 deletions core/src/main/scala/cats/data/Coproduct.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ package data

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

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

import Coproduct._

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

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

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

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

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

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

private[data] sealed abstract class CoproductInstances3 {

implicit def catsDataEqForCoproduct[F[_], G[_], A](implicit E: Eq[F[A] Xor G[A]]): Eq[Coproduct[F, G, A]] =
implicit def catsDataEqForCoproduct[F[_], G[_], A](implicit E: Eq[Either[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
Loading

0 comments on commit 34360f8

Please sign in to comment.