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

Implement EitherT#leftFlatMap and EitherT#leftSemiflatMap #1790

Conversation

vendethiel
Copy link
Contributor

Modeled after the right versions.

@codecov-io
Copy link

codecov-io commented Aug 6, 2017

Codecov Report

Merging #1790 into master will increase coverage by 0.58%.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #1790      +/-   ##
==========================================
+ Coverage   94.96%   95.55%   +0.58%     
==========================================
  Files         241      248       +7     
  Lines        4193     4451     +258     
  Branches      115      118       +3     
==========================================
+ Hits         3982     4253     +271     
+ Misses        211      198      -13
Impacted Files Coverage Δ
core/src/main/scala/cats/data/EitherT.scala 98.36% <100%> (+0.08%) ⬆️
kernel/src/main/scala/cats/kernel/Order.scala 86.48% <0%> (-2.71%) ⬇️
core/src/main/scala/cats/Eval.scala 98.75% <0%> (-1.25%) ⬇️
core/src/main/scala/cats/Monad.scala 96% <0%> (-0.16%) ⬇️
...rc/main/scala/cats/laws/discipline/Arbitrary.scala 92.06% <0%> (-0.13%) ⬇️
core/src/main/scala/cats/data/NonEmptyList.scala 100% <0%> (ø) ⬆️
core/src/main/scala/cats/instances/list.scala 100% <0%> (ø) ⬆️
...ain/scala/cats/laws/discipline/TraverseTests.scala 100% <0%> (ø) ⬆️
core/src/main/scala/cats/instances/order.scala 100% <0%> (ø) ⬆️
...ree/src/main/scala/cats/free/FreeApplicative.scala 100% <0%> (ø) ⬆️
... and 33 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 61d553d...edef908. Read the comment docs.

@kailuowang
Copy link
Contributor

thanks very much! 👍

@kailuowang kailuowang modified the milestone: 1.0.0-RC1 Aug 8, 2017
})

def leftSemiflatMap[D](f: A => F[D])(implicit F: Monad[F]): EitherT[F, D, B] =
leftFlatMap(a => EitherT.left(f(a)))
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 going to allocate the EitherT just to call .value above. Why not just inline the implementation:

EitherT(F.flatMap(value) {
  case Left(a) => f(a).map { d => Left(d) }
  case r@Right(_) => F.pure(r.leftCast)
})

@vendethiel vendethiel force-pushed the feature/either-leftflatmap-leftsemiflatmap branch from 8de4070 to cd38406 Compare August 28, 2017 13:35
@vendethiel
Copy link
Contributor Author

@johnynek Back from holidays. Did just that.

@jrduncans
Copy link

Seems like there should be a leftFlatMap for f: (A) ⇒ F[Either[D, BB]] to fully match flatMap.

@vendethiel
Copy link
Contributor Author

You mean leftFlatMapF?

@jrduncans
Copy link

Oh, yes, that's correct.

@non
Copy link
Contributor

non commented Aug 30, 2017

I'd like to have tests for these in terms of swap and the right-biased methods, e.g.

et.leftFlatMap(a => f(a)) <-> et.swap.flatMap(a => f(a).swap)

Does that seem reasonable?

@vendethiel
Copy link
Contributor Author

vendethiel commented Aug 30, 2017

@non I tried to do it at first, but I missed one swap. It seems to work with one extra:

et.leftFlatMap(a => f(a)) <-> et.swap.flatMap(a => f(a).swap).swap
  • Should I leave the previous test there and add this one, or scratch the one I currently have?
  • And should I try to write a leftSemiflatMap in terms of semiflatMap as well?
  • Should I add leftFlatMapF?

@non
Copy link
Contributor

non commented Aug 31, 2017

@vendethiel Let's add these sorts of tests in addition to what you already have. I'd go ahead and write tests like this for all the left-biased methods that have a right-biased equivalent.

@vendethiel
Copy link
Contributor Author

vendethiel commented Aug 31, 2017

That means 2 foralls per method.

Okay, what about leftFlatMapF, do we want that?

def leftFlatMap[BB >: B, D](f: A => EitherT[F, D, BB])(implicit F: Monad[F]): EitherT[F, D, BB] =
EitherT(F.flatMap(value) {
case Left(a) => f(a).value
case r@Right(_) => F.pure(r.leftCast)
Copy link
Member

Choose a reason for hiding this comment

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

Tiny nitpick, but can we change this to case r: Right => ... since we don't actually want to extract anything?

Copy link
Contributor

Choose a reason for hiding this comment

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

While in practice I don't think it matters, the use of : implies type casing which is generally used in contexts where parametricity is violated: https://typelevel.org/blog/2014/11/10/why_is_adt_pattern_matching_allowed.html

I could have sworn there were some cases where : was allowed and ADT patmat wasn't but I can't remember.

Copy link
Member

Choose a reason for hiding this comment

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

Very interesting article, thanks a lot! :)
I always thought that scalac transforms case t: Type into an isInstanceOf check whereas case Type(_) would be turned into Type.unapply(...), but that article shows that my assumption was false.
It seems then, there's no real benefit to my suggestion, so disregard.

def leftSemiflatMap[D](f: A => F[D])(implicit F: Monad[F]): EitherT[F, D, B] =
EitherT(F.flatMap(value) {
case Left(a) => F.map(f(a)) { d => Left(d) }
case r@Right(_) => F.pure(r.leftCast)
Copy link
Member

Choose a reason for hiding this comment

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

Ditto, as above :)

@kailuowang
Copy link
Contributor

@vendethiel if you waiting for an answer for leftFlatMapF I'd say let's address that in a different PR.

@vendethiel
Copy link
Contributor Author

Okay, thanks. Then I think the PR is ready?

@kailuowang
Copy link
Contributor

kailuowang commented Sep 25, 2017

I still think the tests @non suggested would be valuable to add.

Copy link
Member

@LukaJCB LukaJCB left a comment

Choose a reason for hiding this comment

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

Tiny note, just about naming of tests, otherwise LGTM :)

@@ -434,4 +434,22 @@ class EitherTTests extends CatsSuite {
} yield s1 ++ s2
}

test("leftFlatMap") {
forAll { (eithert: EitherT[List, String, Int], f: String => String) =>
Copy link
Member

Choose a reason for hiding this comment

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

Could we name this one "leftFlatMap consistent with leftMap"?

forAll { (eithert: EitherT[List, String, Int], f: String => String) =>
eithert.leftFlatMap(v => EitherT.left[Int](List(f(v)))) should ===(eithert.leftMap(f))
}
forAll { (eithert: EitherT[List, String, Int], f: String => EitherT[List, String, Int]) =>
Copy link
Member

Choose a reason for hiding this comment

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

How about naming this one "leftFlatMap consistent with swap and then flatMap"?

}
}

test("leftSemiflatMap") {
Copy link
Member

Choose a reason for hiding this comment

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

Same as above for these two tests :)

Tiny nit
@vendethiel
Copy link
Contributor Author

Somehow missed the notifications! Sorry.

@LukaJCB
Copy link
Member

LukaJCB commented Sep 29, 2017

Don't be, it's all good! Thanks very much for your contribution! 😊

@kailuowang
Copy link
Contributor

👍 Thanks very much indeed!

@kailuowang kailuowang merged commit 66b4ac7 into typelevel:master Sep 29, 2017
@vendethiel vendethiel deleted the feature/either-leftflatmap-leftsemiflatmap branch September 29, 2017 13:08
@vendethiel
Copy link
Contributor Author

Thanks! 🍰

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants