Skip to content

Commit

Permalink
Merge pull request #1310 from adelbertc/back-to-either
Browse files Browse the repository at this point in the history
Back to either
  • Loading branch information
adelbertc authored Aug 22, 2016
2 parents 9d1ed49 + 2afeed8 commit f8dfb42
Show file tree
Hide file tree
Showing 52 changed files with 286 additions and 1,917 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.{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]] values.
* Handle errors by turning them into [[scala.util.Either]] 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[Xor[E, A]] = handleErrorWith(
map(fa)(Xor.Right(_): Xor[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
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: 8 additions & 11 deletions core/src/main/scala/cats/arrow/Choice.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package cats
package arrow

import cats.data.Xor
import simulacrum.typeclass

@typeclass trait Choice[F[_, _]] extends Category[F] {
Expand All @@ -12,37 +11,35 @@ 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: Xor[Boolean, 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: (Xor[Int, 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.{Coproduct, Xor}
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
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 [[cats.data.Xor]].
/** `F` on the left and `G` on the right of [[scala.util.Either]].
*
* @param run The underlying [[cats.data.Xor]].
* @param run The underlying [[scala.util.Either]].
*/
final case class Coproduct[F[_], G[_], A](run: Xor[F[A], 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: Xor[F[A], 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[Xor[F[A], 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
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, Xor[L, A]] = EitherT.right(F.map(fla.value)(_.toXor))
override def attempt[A](fla: EitherT[F, L, A]): EitherT[F, L, Either[L, A]] = EitherT.right(fla.value)
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
13 changes: 6 additions & 7 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 `Xor[A, B]`, except that it can represent the simultaneous presence of
* `A [[Ior]] B` is similar to `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 [[toXor]], ignore the `A` value in a [[Ior.Both Both]].
* `[[Semigroup]][A]`, while other methods, like [[toEither]], ignore the `A` value in a [[Ior.Both Both]].
*
* `A [[Ior]] B` is isomorphic to `Xor[Xor[A, B], (A, B)]`, but provides methods biased toward `B`
* `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 [[cats.data.Xor]] form can be accessed via the [[unwrap]] method.
* The isomorphic [[scala.util.Either]] form can be accessed via the [[unwrap]] method.
*/
sealed abstract class Ior[+A, +B] extends Product with Serializable {

Expand All @@ -36,12 +36,11 @@ 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[Xor[A, B]] = fold(a => Some(Xor.Left(a)), b => Some(Xor.Right(b)), (_, _) => None)
final def onlyLeftOrRight: Option[Either[A, B]] = fold(a => Some(Left(a)), b => Some(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: 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 unwrap: Either[Either[A, B], (A, B)] = fold(a => Left(Left(a)), b => Left(Right(b)), (a, b) => 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))
final def toOption: Option[B] = right
final def toList: List[B] = right.toList
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, Xor[A, B], C] =
def choice[A, B, C](f: Kleisli[F, A, C], g: Kleisli[F, B, C]): Kleisli[F, Either[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]): XorT[F, L, A] =
XorT(cata(Xor.Left(left), Xor.Right.apply))
def toRight[L](left: => L)(implicit F: Functor[F]): EitherT[F, L, A] =
EitherT(cata(Left(left), Right.apply))

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

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

Expand Down
18 changes: 4 additions & 14 deletions core/src/main/scala/cats/data/Validated.scala
Original file line number Diff line number Diff line change
Expand Up @@ -75,16 +75,11 @@ sealed abstract class Validated[+E, +A] extends Product with Serializable {
}

/**
* Convert this value to RightOr if Valid or LeftOr if Invalid
* Convert to an Either, apply a function, convert back. This is handy
* when you want to use the Monadic properties of the Either type.
*/
def toXor: Xor[E, A] = fold(Xor.Left.apply, Xor.Right.apply)

/**
* 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 withXor[EE, B](f: Xor[E, A] => Xor[EE, B]): Validated[EE, B] =
Validated.fromXor(f(toXor))
def withEither[EE, B](f: Either[E, A] => Either[EE, B]): Validated[EE, B] =
Validated.fromEither(f(toEither))

/**
* Validated is a [[functor.Bifunctor]], this method applies one of the
Expand Down Expand Up @@ -391,11 +386,6 @@ 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
Loading

0 comments on commit f8dfb42

Please sign in to comment.