Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Partially revert 4530d3aa93131ec28096968a3c903ed1016dbf1b. Add back v… #1506

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 11 additions & 10 deletions core/src/main/scala/cats/data/EitherT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,19 @@ final case class EitherT[F[_], A, B](value: F[Either[A, B]]) {

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

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

def getOrElseF(default: => F[B])(implicit F: Monad[F]): F[B] = {
def getOrElseF[BB >: B](default: => F[BB])(implicit F: Monad[F]): F[BB] = {
F.flatMap(value) {
case Left(_) => default
case Right(b) => F.pure(b)
}
}

def orElse(default: => EitherT[F, A, B])(implicit F: Monad[F]): EitherT[F, A, B] = {
def orElse[AA, BB >: B](default: => EitherT[F, AA, BB])(implicit F: Monad[F]): EitherT[F, AA, BB] = {
EitherT(F.flatMap(value) {
case Left(_) => default.value
case r @ Right(_) => F.pure(r)
case r @ Right(_) => F.pure(r.leftCast)
})
}

Expand All @@ -46,13 +46,14 @@ final case class EitherT[F[_], A, B](value: F[Either[A, B]]) {
case other => F.pure(other)
})

def valueOr(f: A => B)(implicit F: Functor[F]): F[B] = fold(f, identity)
def valueOr[BB >: B](f: A => BB)(implicit F: Functor[F]): F[BB] = fold(f, identity)

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 ensure(onFailure: => A)(f: B => Boolean)(implicit F: Functor[F]): EitherT[F, A, B] = EitherT(F.map(value)(_.ensure(onFailure)(f)))
def ensure[AA >: A](onFailure: => AA)(f: B => Boolean)(implicit F: Functor[F]): EitherT[F, AA, B] =
EitherT(F.map(value)(_.ensure(onFailure)(f)))

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

Expand All @@ -70,19 +71,19 @@ final case class EitherT[F[_], A, B](value: F[Either[A, B]]) {
def applyAlt[D](ff: EitherT[F, A, B => D])(implicit F: Apply[F]): EitherT[F, A, D] =
EitherT[F, A, D](F.map2(this.value, ff.value)((xb, xbd) => Apply[Either[A, ?]].ap(xbd)(xb)))

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

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

def transform[C, D](f: Either[A, B] => Either[C, D])(implicit F: Functor[F]): EitherT[F, C, D] =
EitherT(F.map(value)(f))

def subflatMap[D](f: B => Either[A, D])(implicit F: Functor[F]): EitherT[F, A, D] =
def subflatMap[AA >: A, D](f: B => Either[AA, D])(implicit F: Functor[F]): EitherT[F, AA, D] =
transform(_.flatMap(f))

def map[D](f: B => D)(implicit F: Functor[F]): EitherT[F, A, D] = bimap(identity, f)
Expand Down Expand Up @@ -110,7 +111,7 @@ final case class EitherT[F[_], A, B](value: F[Either[A, B]]) {
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(implicit ev: B <:< A, F: Functor[F]): F[A] = F.map(value)(_.fold(identity, ev.apply))
def merge[AA >: A](implicit ev: B <:< AA, F: Functor[F]): F[AA] = F.map(value)(_.fold(identity, ev.apply))

/**
* Similar to `Either#combine` but mapped over an `F` context.
Expand Down
50 changes: 25 additions & 25 deletions core/src/main/scala/cats/syntax/either.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,27 +23,27 @@ final class EitherOps[A, B](val eab: Either[A, B]) extends AnyVal {
case Right(b) => f(b)
}

def getOrElse(default: => B): B = eab match {
def getOrElse[BB >: B](default: => BB): BB = eab match {
case Left(_) => default
case Right(b) => b
}

def orElse[C](fallback: => Either[C, B]): Either[C, B] = eab match {
def orElse[C, BB >: B](fallback: => Either[C, BB]): Either[C, BB] = eab match {
case Left(_) => fallback
case r @ Right(_) => EitherUtil.leftCast(r)
}

def recover(pf: PartialFunction[A, B]): Either[A, B] = eab match {
def recover[BB >: B](pf: PartialFunction[A, BB]): Either[A, BB] = eab match {
case Left(a) if pf.isDefinedAt(a) => Right(pf(a))
case _ => eab
}

def recoverWith(pf: PartialFunction[A, Either[A, B]]): Either[A, B] = eab match {
def recoverWith[AA >: A, BB >: B](pf: PartialFunction[A, Either[AA, BB]]): Either[AA, BB] = eab match {
case Left(a) if pf.isDefinedAt(a) => pf(a)
case _ => eab
}

def valueOr(f: A => B): B = eab match {
def valueOr[BB >: B](f: A => BB): BB = eab match {
case Left(a) => f(a)
case Right(b) => b
}
Expand All @@ -58,7 +58,7 @@ final class EitherOps[A, B](val eab: Either[A, B]) extends AnyVal {
case Right(b) => f(b)
}

def ensure(onFailure: => A)(f: B => Boolean): Either[A, B] = eab match {
def ensure[AA >: A](onFailure: => AA)(f: B => Boolean): Either[AA, B] = eab match {
case Left(_) => eab
case Right(b) => if (f(b)) eab else Left(onFailure)
}
Expand Down Expand Up @@ -90,7 +90,7 @@ final class EitherOps[A, B](val eab: Either[A, B]) extends AnyVal {

/** Returns a [[cats.data.ValidatedNel]] representation of this disjunction with the `Left` value
* as a single element on the `Invalid` side of the [[cats.data.NonEmptyList]]. */
def toValidatedNel: ValidatedNel[A, B] = eab match {
def toValidatedNel[AA >: A]: ValidatedNel[AA, B] = eab match {
case Left(a) => Validated.invalidNel(a)
case Right(b) => Validated.valid(b)
}
Expand All @@ -113,7 +113,7 @@ final class EitherOps[A, B](val eab: Either[A, B]) extends AnyVal {
case Right(b) => Right(f(b))
}

def map2Eval[C, Z](fc: Eval[Either[A, C]])(f: (B, C) => Z): Eval[Either[A, Z]] =
def map2Eval[AA >: A, C, Z](fc: Eval[Either[AA, C]])(f: (B, C) => Z): Eval[Either[AA, Z]] =
eab match {
case l @ Left(_) => Now(EitherUtil.rightCast(l))
case Right(b) => fc.map(either => new EitherOps(either).map(f(b, _)))
Expand All @@ -124,51 +124,51 @@ final class EitherOps[A, B](val eab: Either[A, B]) extends AnyVal {
case r @ Right(_) => EitherUtil.leftCast(r)
}

def flatMap[D](f: B => Either[A, D]): Either[A, D] = eab match {
def flatMap[AA >: A, D](f: B => Either[AA, D]): Either[AA, D] = eab match {
case l @ Left(_) => EitherUtil.rightCast(l)
case Right(b) => f(b)
}

def compare(that: Either[A, B])(implicit A: Order[A], B: Order[B]): Int = eab match {
def compare[AA >: A, BB >: B](that: Either[AA, BB])(implicit AA: Order[AA], BB: Order[BB]): Int = eab match {
case Left(a1) =>
that match {
case Left(a2) => A.compare(a1, a2)
case Left(a2) => AA.compare(a1, a2)
case Right(_) => -1
}
case Right(b1) =>
that match {
case Left(_) => 1
case Right(b2) => B.compare(b1, b2)
case Right(b2) => BB.compare(b1, b2)
}
}

def partialCompare(that: Either[A, B])(implicit A: PartialOrder[A], B: PartialOrder[B]): Double = eab match {
def partialCompare[AA >: A, BB >: B](that: Either[AA, BB])(implicit AA: PartialOrder[AA], BB: PartialOrder[BB]): Double = eab match {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this method is untested. Is it too much to ask to write a test of some kind during this PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not at all. Will do

Copy link
Contributor Author

@marcin-rzeznicki marcin-rzeznicki Dec 30, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually this one should be covered by order laws at https://github.com/typelevel/cats/blob/master/tests/src/test/scala/cats/tests/EitherTests.scala#L44 , right?

EDIT: Ah, it isn't because implementation of partialCompare in EitherInstances is duplicated in EitherOps. Is it better to dedup these two?

case Left(a1) =>
that match {
case Left(a2) => A.partialCompare(a1, a2)
case Left(a2) => AA.partialCompare(a1, a2)
case Right(_) => -1
}
case Right(b1) =>
that match {
case Left(_) => 1
case Right(b2) => B.partialCompare(b1, b2)
case Right(b2) => BB.partialCompare(b1, b2)
}
}

def ===(that: Either[A, B])(implicit A: Eq[A], B: Eq[B]): Boolean = eab match {
def ===[AA >: A, BB >: B](that: Either[AA, BB])(implicit AA: Eq[AA], BB: Eq[BB]): Boolean = eab match {
case Left(a1) =>
that match {
case Left(a2) => A.eqv(a1, a2)
case Left(a2) => AA.eqv(a1, a2)
case Right(_) => false
}
case Right(b1) =>
that match {
case Left(_) => false
case Right(b2) => B.eqv(b1, b2)
case Right(b2) => BB.eqv(b1, b2)
}
}

def traverse[F[_], D](f: B => F[D])(implicit F: Applicative[F]): F[Either[A, D]] = eab match {
def traverse[F[_], AA >: A, D](f: B => F[D])(implicit F: Applicative[F]): F[Either[AA, D]] = eab match {
case l @ Left(_) => F.pure(EitherUtil.rightCast(l))
case Right(b) => F.map(f(b))(Right(_))
}
Expand Down Expand Up @@ -215,20 +215,20 @@ final class EitherOps[A, B](val eab: Either[A, B]) extends AnyVal {
* res3: Either[String, Int] = Right(7)
* }}}
*/
final def combine(that: Either[A, B])(implicit B: Semigroup[B]): Either[A, B] = eab match {
final def combine[AA >: A, BB >: B](that: Either[AA, BB])(implicit BB: Semigroup[BB]): Either[AA, BB] = eab match {
case left @ Left(_) => left
case Right(b1) => that match {
case left @ Left(_) => left
case Right(b2) => Right(B.combine(b1, b2))
case Right(b2) => Right(BB.combine(b1, b2))
}
}

def show(implicit A: Show[A], B: Show[B]): String = eab match {
case Left(a) => s"Left(${A.show(a)})"
case Right(b) => s"Right(${B.show(b)})"
def show[AA >: A, BB >: B](implicit AA: Show[AA], BB: Show[BB]): String = eab match {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is untested. Can we add a simple test?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of course

case Left(a) => s"Left(${AA.show(a)})"
case Right(b) => s"Right(${BB.show(b)})"
}

def ap[C](that: Either[A, B => C]): Either[A, C] = (new EitherOps(that)).flatMap(this.map)
def ap[AA >: A, BB >: B, C](that: Either[AA, BB => C]): Either[AA, C] = new EitherOps(that).flatMap(this.map)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is untested. Can we add a simple test?


/**
* Transform the `Either` into a [[cats.data.EitherT]] while lifting it into the specified Applicative.
Expand Down