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

Change forEffect/followedBy to productL/productR #2083

Merged
merged 18 commits into from
Dec 15, 2017
Merged

Change forEffect/followedBy to productL/productR #2083

merged 18 commits into from
Dec 15, 2017

Conversation

Jacoby6000
Copy link
Contributor

@Jacoby6000 Jacoby6000 commented Dec 8, 2017

This should resolve #1983.

I picked apL and apR based on discussion in that issue.

The deprecation caused scalac to complain about the code generated by simulacrum, so I moved the deprecated method aliases in to syntax.apply.

Copy link

@emilypi emilypi left a comment

Choose a reason for hiding this comment

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

LGTM

@Jacoby6000
Copy link
Contributor Author

Just realized I missed a bunch of other methods. working on that.

@kailuowang kailuowang added this to the 1.0.0 milestone Dec 8, 2017
@kailuowang
Copy link
Contributor

Thanks! @Jacoby6000, a scalafix migration would be handy. Let me know if you are interested in giving it a try or I can add it in a follow-up PR. Here is a good example for such rename migrations.

@kailuowang
Copy link
Contributor

also, we won't have RC2, so all the deprecation note should be 1.0.0

@Jacoby6000
Copy link
Contributor Author

Jacoby6000 commented Dec 8, 2017

@kailuowang I built the scalafix stuff, but it seems to cause some problems. forEffect and followedBy were introduced during 1.0.0, and I'm not sure how to split up the fix migrations. I've pushed my scalafix work in to #2083-scalafix.

@kailuowang
Copy link
Contributor

The problem is that the Scalafix test depends on 0.9 right? I would say for this PR we simply don't test this migration. It should be low risk

@ceedubs
Copy link
Contributor

ceedubs commented Dec 9, 2017

👍 once there is resolution on the scalafix rules.

I don't think that any word-based name is going to be perfect, but apL and apR seem less likely to cause confusion with certain effect types.

@Jacoby6000
Copy link
Contributor Author

I've added in the scalafix stuff that I drafted. I can't test it, so please look it over 😅

@kailuowang
Copy link
Contributor

kailuowang commented Dec 10, 2017

for the scalafix stuff, if you include the input and output they will be compiled, which fails due to mis-dependency as we discussed earlier. Sorry I wasn't clear, by "don't test" I mean we shouldn't include them in the input and output of the scalafix tests. Also bin compact check failed, need to add mima exceptions ( you can check CI log to see which ones are needed, or you can leave that to us).

@Qi77Qi
Copy link

Qi77Qi commented Dec 13, 2017

Think faq page needs to be updated as well?

@kailuowang
Copy link
Contributor

close and reopen to trigger build

@LukaJCB LukaJCB closed this Dec 14, 2017
@LukaJCB LukaJCB reopened this Dec 14, 2017
LukaJCB
LukaJCB previously approved these changes Dec 14, 2017
@johnynek
Copy link
Contributor

I’m -1 on apL and apR the more I think about it. Note we already have ap. And these new methods are not that similar. I would say productR and productL are much better.

@kailuowang
Copy link
Contributor

kailuowang commented Dec 14, 2017

I am fine with productR and productL, but if people can't agree on it soon, I would propose we give up on bikeshedding this one and just leave as is (closing this PR).

@Jacoby6000
Copy link
Contributor Author

Jacoby6000 commented Dec 14, 2017

I'm not much of a fan of productL and productR, mainly because I don't really like product, either. To me, product intuitively means tuple.. So, that method makes me think a -> b -> (a, b), not f a -> f b -> f (a, b). Additionally product does not really convey the application of effects and the standard lib also has a product method which interferes.

As for the methods not being related, I think their relationship becomes more clear if you define map2 more traditionally, and then apL/apR in terms of that.

As an aside, product should probably be rewritten in terms of map2, not the other way around as it is now.

def apL[F[_]: Apply, A, B](fa: F[A])(fb: F[B]): F[A] =
  map2(fa, fb)((a, _) => a)

def apR[F[_]: Apply, A, B](fa: F[A])(fb: F[B]): F[B] =
  map2(fa, fb)((_, b) => b)

def map2[F[_], A, B, C](fa: F[A], fb: F[B])(f: (A, B) => C)(implicit F: Apply[F]): F[C] = 
  F.ap(F.map(fa)(a => (b: B) => f(a, b)))(fb)

@Jacoby6000
Copy link
Contributor Author

Jacoby6000 commented Dec 14, 2017

I'm willing to submit and change it to productL and productR to appease the community; I only ever use the proper notation anyway.

@Jacoby6000
Copy link
Contributor Author

Jacoby6000 commented Dec 14, 2017

Going deeper in to the relationship, and why I think apL and apR are better than productL and productR:

  • <*> is ap.
  • *> is apR which applies both effects, as ap does, but only retains the value on the right.
  • <* is apL which applies both effects, as ap does, but only retains the value on the left.

I think having names which are as analagous as the symbols does a great deal towards teaching the notation. If people never use <*> or *> or <*, but instead opt for ap, apR, and apL, they will be better off whenever they move to a system using more traditional notation (like, if they learn haskell for instance). Once they realize that <*> is ap, the understanding of *> and <* will come more easily, and vice versa.

@johnynek
Copy link
Contributor

I agree with some of what you say, I feel like you are overlooking that ap is dealing with a A => B at some point: F[A => B] <*> F[A]: F[B]. The name is related to apply which is about (A => B) apply A: B. So, keeping ap about apply from A => B when there is no function in sight, to me is a bad name.

I hear you that you don't like product, but that is the name we have for F[A], F[B] => F[(A, B)]. To me, the types there are much closer to what we have at hand.

If you don't like them, I'm pretty happy to keep the current names since I think as long as names don't mislead (and I feel apR and apL do), I don't think they matter too much, so forEffect is just a pointer to the docs which often has a good mnemonic. To me, that's fine.

@Jacoby6000
Copy link
Contributor Author

I'm going to update this PR to use productL and productR, specifically because cats already has product (which I have said before). Ultimately my agreement is of little consequence. Besides that, just about anything is better than what is there currently.

@kailuowang
Copy link
Contributor

kailuowang commented Dec 14, 2017

@Jacoby6000 thanks very much! Hate to ask you one more thing, we ended up deciding that we are going to have a quick 1.0.0-RC2 release, so if it's easy for you, would you update the deprecate versions? I'd be happy to change those for you if you don't have the time.

@Jacoby6000
Copy link
Contributor Author

I'll have time in a few hours, if it can wait.

johnynek
johnynek previously approved these changes Dec 15, 2017
@Jacoby6000 Jacoby6000 changed the title Change forEffect/followedBy to apL/apR Change forEffect/followedBy to productL/productR Dec 15, 2017
@@ -62,7 +63,7 @@ trait Apply[F[_]] extends Functor[F] with Semigroupal[F] with ApplyArityFunction
* map2 can be seen as a binary version of [[cats.Functor]]#map.
*/
def map2[A, B, Z](fa: F[A], fb: F[B])(f: (A, B) => Z): F[Z] =
map(product(fa, fb)) { case (a, b) => f(a, b) }
ap(map(fa)(a => (b: B) => f(a, b)))(fb)
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 a sensible improvement if we only consider the default implementation, but many instances overrides product for better performance. So we might want to keep the original implementation of product and map2

Copy link
Contributor

Choose a reason for hiding this comment

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

actually the law is broken with Const instance which overrides product

ConstSuite:
[info]
[info] - Apply[Const[NonEmptyList[String], Int]].apply.map2/product-map consistency *** FAILED ***
[info] GeneratorDrivenPropertyCheckFailedException was thrown during property evaluation.
[info] (Discipline.scala:14)
[info] Falsified after 3 successful property evaluations.
[info] Location: (Discipline.scala:14)
[info] Occurred when passed generated values (
[info] arg0 = Const(NonEmptyList(ꙫ, 鰓)),
[info] arg1 = Const(NonEmptyList(, )),
[info] arg2 =
[info] )
[info] Label of failing property:
[info] Expected: Const(NonEmptyList(, , ꙫ, 鰓))
[info] Received: Const(NonEmptyList(ꙫ, 鰓, , ))

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah Yeah, that was a bit short sighted of me. I didn't consider overrides.

@kailuowang
Copy link
Contributor

Thanks very much! @Jacoby6000

@LukaJCB
Copy link
Member

LukaJCB commented Dec 15, 2017

Yes, thanks a lot, Jacob! :)

@LukaJCB LukaJCB merged commit 8120890 into typelevel:master Dec 15, 2017
"_root_.cats.NonEmptyParallel.parFollowedBy." -> "parApR",
"_root_.cats.FlatMap.forEffectEval." -> "apLEval",
"_root_.cats.FlatMap.followedByEval." -> "apREval",
)
Copy link
Collaborator

Choose a reason for hiding this comment

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

These rewrite rules still need to be updated to productR/productL, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah yep, they sure do. I missed those.

Copy link
Contributor

Choose a reason for hiding this comment

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

fix submitted #2117

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.

Rename followedBy and effectFor
10 participants