-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
added leftT and improved existing lift API for EitherT #1614
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -89,7 +89,7 @@ final case class EitherT[F[_], A, B](value: F[Either[A, B]]) { | |
def map[D](f: B => D)(implicit F: Functor[F]): EitherT[F, A, D] = bimap(identity, f) | ||
|
||
def semiflatMap[D](f: B => F[D])(implicit F: Monad[F]): EitherT[F, A, D] = | ||
flatMap(b => EitherT.right[F, A, D](f(b))) | ||
flatMap(b => EitherT.right(f(b))) | ||
|
||
def leftMap[C](f: A => C)(implicit F: Functor[F]): EitherT[F, C, B] = bimap(f, identity) | ||
|
||
|
@@ -236,11 +236,78 @@ final case class EitherT[F[_], A, B](value: F[Either[A, B]]) { | |
object EitherT extends EitherTInstances with EitherTFunctions | ||
|
||
private[data] trait EitherTFunctions { | ||
final def left[F[_], A, B](fa: F[A])(implicit F: Functor[F]): EitherT[F, A, B] = EitherT(F.map(fa)(Either.left)) | ||
|
||
final def right[F[_], A, B](fb: F[B])(implicit F: Functor[F]): EitherT[F, A, B] = EitherT(F.map(fb)(Either.right)) | ||
final class LeftPartiallyApplied[B] private[EitherTFunctions] { | ||
def apply[F[_], A](fa: F[A])(implicit F: Functor[F]): EitherT[F, A, B] = EitherT(F.map(fa)(Either.left)) | ||
} | ||
|
||
/** | ||
* Creates a left version of `EitherT[F, A, B]` from a `F[A]` | ||
* {{{ | ||
* scala> import cats.data.EitherT | ||
* scala> import cats.implicits._ | ||
* scala> EitherT.left[Int](Option("err")) | ||
* res0: cats.data.EitherT[Option,String,Int] = EitherT(Some(Left(err))) | ||
* }}} | ||
*/ | ||
final def left[B]: LeftPartiallyApplied[B] = new LeftPartiallyApplied[B] | ||
|
||
final class LeftTPartiallyApplied[F[_], B] private[EitherTFunctions] { | ||
def apply[A](a: A)(implicit F: Applicative[F]): EitherT[F, A, B] = EitherT(F.pure(Either.left(a))) | ||
} | ||
|
||
/** | ||
* Creates a left version of `EitherT[F, A, B]` from a `A` | ||
* {{{ | ||
* scala> import cats.data.EitherT | ||
* scala> import cats.implicits._ | ||
* scala> EitherT.leftT[Option, Int]("err") | ||
* res0: cats.data.EitherT[Option,String,Int] = EitherT(Some(Left(err))) | ||
* }}} | ||
*/ | ||
final def leftT[F[_], B]: LeftTPartiallyApplied[F, B] = new LeftTPartiallyApplied[F, B] | ||
|
||
final class RightPartiallyApplied[A] private[EitherTFunctions] { | ||
def apply[F[_], B](fb: F[B])(implicit F: Functor[F]): EitherT[F, A, B] = EitherT(F.map(fb)(Either.right)) | ||
} | ||
|
||
/** | ||
* Creates a right version of `EitherT[F, A, B]` from a `F[B]` | ||
* {{{ | ||
* scala> import cats.data.EitherT | ||
* scala> import cats.implicits._ | ||
* scala> EitherT.right[String](Option(3)) | ||
* res0: cats.data.EitherT[Option,String,Int] = EitherT(Some(Right(3))) | ||
* }}} | ||
*/ | ||
final def right[A]: RightPartiallyApplied[A] = new RightPartiallyApplied[A] | ||
|
||
final class PurePartiallyApplied[F[_], A] private[EitherTFunctions] { | ||
def apply[B](b: B)(implicit F: Applicative[F]): EitherT[F, A, B] = right(F.pure(b)) | ||
} | ||
|
||
/** | ||
* Creates a new `EitherT[F, A, B]` from a `B` | ||
* {{{ | ||
* scala> import cats.data.EitherT | ||
* scala> import cats.implicits._ | ||
* scala> EitherT.pure[Option, String](3) | ||
* res0: cats.data.EitherT[Option,String,Int] = EitherT(Some(Right(3))) | ||
* }}} | ||
*/ | ||
final def pure[F[_], A]: PurePartiallyApplied[F, A] = new PurePartiallyApplied[F, A] | ||
|
||
/** | ||
* Alias for [[pure]] | ||
* {{{ | ||
* scala> import cats.data.EitherT | ||
* scala> import cats.implicits._ | ||
* scala> EitherT.rightT[Option, String](3) | ||
* res0: cats.data.EitherT[Option,String,Int] = EitherT(Some(Right(3))) | ||
* }}} | ||
*/ | ||
final def rightT[F[_], A]: PurePartiallyApplied[F, A] = pure | ||
|
||
final def pure[F[_], A, B](b: B)(implicit F: Applicative[F]): EitherT[F, A, B] = right(F.pure(b)) | ||
|
||
/** | ||
* Alias for [[right]] | ||
|
@@ -295,6 +362,19 @@ private[data] trait EitherTFunctions { | |
EitherT(F.pure(Either.fromOption(opt, ifNone))) | ||
} | ||
|
||
/** Transforms an `F[Option]` into an `EitherT`, using the second argument if the `Option` is a `None`. | ||
* {{{ | ||
* scala> import cats.implicits._ | ||
* scala> val o: Option[Int] = None | ||
* scala> EitherT.fromOptionF(List(o), "Answer not known.") | ||
* res0: EitherT[List, String, Int] = EitherT(List(Left(Answer not known.))) | ||
* scala> EitherT.fromOptionF(List(Option(42)), "Answer not known.") | ||
* res1: EitherT[List, String, Int] = EitherT(List(Right(42))) | ||
* }}} | ||
*/ | ||
final def fromOptionF[F[_], E, A](fopt: F[Option[A]], ifNone: => E)(implicit F: Functor[F]): EitherT[F, E, A] = | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just wondering, is this better than There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Didn't know about the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @peterneyens anything else in this PR? |
||
EitherT(F.map(fopt)(opt => Either.fromOption(opt, ifNone))) | ||
|
||
/** If the condition is satisfied, return the given `A` in `Right` | ||
* lifted into the specified `Applicative`, otherwise, return the | ||
* given `E` in `Left` lifted into the specified `Applicative`. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am curious. Is Scalaz's trick here (add a dummy parameter to this class to make it an
AnyVal
; see here) necessary to make this zero-cost?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That seems a nice trick. Do we want to use it here first in this PR, or create another PR applying the pattern globally?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm okay with another PR to apply it globally.