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

feat: add .toEitherT to Validated #4554

Closed
wants to merge 2 commits into from
Closed

feat: add .toEitherT to Validated #4554

wants to merge 2 commits into from

Conversation

jeengbe
Copy link

@jeengbe jeengbe commented Jan 27, 2024

Similar to .toEither but with EitherT

* Example:
* {{{
* scala> import cats.syntax.all._
* scala> given ExecutionContext = ExecutionContext.global
Copy link
Author

Choose a reason for hiding this comment

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

I believe this is Scala 3 syntax, please replace it with the Scala 2 equivalent (which I assume doc comments are written in)

Copy link
Member

Choose a reason for hiding this comment

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

Didn't compile it myself, but I think this would do it:

Suggested change
* scala> given ExecutionContext = ExecutionContext.global
* scala> import scala.concurrent.ExecutionContext.Implicits.global

@jeengbe
Copy link
Author

jeengbe commented Jan 27, 2024

Hm, the errors correctly mark:

[error] /home/runner/work/cats/cats/core/src/main/scala/cats/data/Validated.scala:286:7: covariant type E occurs in invariant position in type [F[_]](implicit evidence$1: cats.Applicative[F]): cats.data.EitherT[F,E,A] of method toEitherT
[error]   def toEitherT[F[_]: Applicative]: EitherT[F, E, A] =
[error]       ^

yet with an extension, this variance difference is no issue:

extension [E, A](validated: Validated[E, A])
  def toEitherT[F[_]: Applicative]: EitherT[F, E, A] = validated match
    case Validated.Invalid(e) => EitherT.leftT(e)
    case Validated.Valid(a)   => EitherT.rightT(a)

I have unfortunately not the slightest idea how to fix this

Comment on lines +287 to +290
this match {
case Invalid(e) => EitherT.leftT(e)
case Valid(a) => EitherT.rightT(a)
}
Copy link
Author

Choose a reason for hiding this comment

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

And perhaps

Suggested change
this match {
case Invalid(e) => EitherT.leftT(e)
case Valid(a) => EitherT.rightT(a)
}
EitherT.fromEither(this.toEither)

is cleaner

Copy link
Member

@rossabaker rossabaker left a comment

Choose a reason for hiding this comment

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

Thanks for the contribution! The compilation error can be fixed with:

  def toEitherT[F[_]: Applicative, EE >: E, AA >: A]: EitherT[F, EE, AA] =

... but that's not what we want, because then .toEitherT needs three parameters, and it loses its convenience. I thought Ior.toIorT might serve as prior art, but it doesn't exist. But IorT.fromIor does! Maybe what we want is EitherT.fromValidated?

* Example:
* {{{
* scala> import cats.syntax.all._
* scala> given ExecutionContext = ExecutionContext.global
Copy link
Member

Choose a reason for hiding this comment

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

Didn't compile it myself, but I think this would do it:

Suggested change
* scala> given ExecutionContext = ExecutionContext.global
* scala> import scala.concurrent.ExecutionContext.Implicits.global

@@ -319,7 +319,7 @@ FormValidatorNec.validateForm(
firstName = "John",
lastName = "Doe",
age = 5
).toEither
Copy link
Member

Choose a reason for hiding this comment

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

The next sentence says we have an Either. Perhaps it's better to make the EitherT a separate example?

@satorg
Copy link
Contributor

satorg commented Jan 29, 2024

Maybe what we want is EitherT.fromValidated?

Agree. Adding a new constructor to EitherT seems more coherent taking into account that it already offers constructors like fromEither, fromOption and some others.

Another thought is that EitherT is more complex type comparing to Validated, so I personally feel that making more complex abstractions depending on more basic ones is usually preferable that doing the opposite.

@jeengbe
Copy link
Author

jeengbe commented Jan 29, 2024

Thanks for outlining the reasoning, I agree.

@jeengbe jeengbe closed this Jan 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants