From e54119db9418eaa561ee20c6ea032859cb8f9d8f Mon Sep 17 00:00:00 2001 From: Jacob Barber Date: Fri, 8 Dec 2017 15:21:59 -0600 Subject: [PATCH 01/14] Change forEffect/followedBy to apL/apR. Depricated old methods, added <*>. --- core/src/main/scala/cats/Apply.scala | 28 ++++++++-------- core/src/main/scala/cats/FlatMap.scala | 2 +- .../src/main/scala/cats/instances/tuple.scala | 4 +-- core/src/main/scala/cats/syntax/apply.scala | 32 +++++++++++++++++++ core/src/main/scala/cats/syntax/flatMap.scala | 2 +- laws/src/main/scala/cats/laws/ApplyLaws.scala | 6 ++-- 6 files changed, 54 insertions(+), 20 deletions(-) diff --git a/core/src/main/scala/cats/Apply.scala b/core/src/main/scala/cats/Apply.scala index a91a1086f4..0679206067 100644 --- a/core/src/main/scala/cats/Apply.scala +++ b/core/src/main/scala/cats/Apply.scala @@ -1,6 +1,6 @@ package cats -import simulacrum.typeclass +import simulacrum.{typeclass, noop} /** * Weaker version of Applicative[F]; has apply but not pure. @@ -16,24 +16,26 @@ trait Apply[F[_]] extends Functor[F] with Semigroupal[F] with ApplyArityFunction */ def ap[A, B](ff: F[A => B])(fa: F[A]): F[B] - override def product[A, B](fa: F[A], fb: F[B]): F[(A, B)] = - ap(map(fa)(a => (b: B) => (a, b)))(fb) - /** Compose two actions, discarding any value produced by the first. */ - def followedBy[A, B](fa: F[A])(fb: F[B]): F[B] = + def apR[A, B](fa: F[A])(fb: F[B]): F[B] = map2(fa, fb)((_, b) => b) - /** Alias for [[followedBy]]. */ - @inline final def *>[A, B](fa: F[A])(fb: F[B]): F[B] = - followedBy(fa)(fb) - /** Compose two actions, discarding any value produced by the second. */ - def forEffect[A, B](fa: F[A])(fb: F[B]): F[A] = + def apL[A, B](fa: F[A])(fb: F[B]): F[A] = map2(fa, fb)((a, _) => a) - /** Alias for [[forEffect]]. */ - @inline final def <*[A, B](fa: F[A])(fb: F[B]): F[A] = - forEffect(fa)(fb) + override def product[A, B](fa: F[A], fb: F[B]): F[(A, B)] = + ap(map(fa)(a => (b: B) => (a, b)))(fb) + + /** Alias for [[apR]]. */ + @deprecated("Use *> or apR instead.", "1.0.0-RC2") + @noop @inline final def followedBy[A, B](fa: F[A])(fb: F[B]): F[B] = + apR(fa)(fb) + + /** Alias for [[apL]]. */ + @deprecated("Use <* or apL instead.", "1.0.0-RC2") + @noop @inline final def forEffect[A, B](fa: F[A])(fb: F[B]): F[A] = + apL(fa)(fb) /** * ap2 is a binary version of ap, defined in terms of ap. diff --git a/core/src/main/scala/cats/FlatMap.scala b/core/src/main/scala/cats/FlatMap.scala index cec786c763..211c7c39dd 100644 --- a/core/src/main/scala/cats/FlatMap.scala +++ b/core/src/main/scala/cats/FlatMap.scala @@ -43,7 +43,7 @@ import simulacrum.typeclass /** * Sequentially compose two actions, discarding any value produced by the first. This variant of - * [[followedBy]] also lets you define the evaluation strategy of the second action. For instance + * [[apR]] also lets you define the evaluation strategy of the second action. For instance * you can evaluate it only ''after'' the first action has finished: * * {{{ diff --git a/core/src/main/scala/cats/instances/tuple.scala b/core/src/main/scala/cats/instances/tuple.scala index ffa103c001..5bef7a3f6e 100644 --- a/core/src/main/scala/cats/instances/tuple.scala +++ b/core/src/main/scala/cats/instances/tuple.scala @@ -110,10 +110,10 @@ private[instances] class FlatMapTuple2[X](s: Semigroup[X]) extends FlatMap[(X, ? (x, xb._2) } - override def followedBy[A, B](a: (X, A))(b: (X, B)): (X, B) = + override def apR[A, B](a: (X, A))(b: (X, B)): (X, B) = (s.combine(a._1, b._1), b._2) - override def forEffect[A, B](a: (X, A))(b: (X, B)): (X, A) = + override def apL[A, B](a: (X, A))(b: (X, B)): (X, A) = (s.combine(a._1, b._1), a._2) override def mproduct[A, B](fa: (X, A))(f: A => (X, B)): (X, (A, B)) = { diff --git a/core/src/main/scala/cats/syntax/apply.scala b/core/src/main/scala/cats/syntax/apply.scala index 244766a310..3e2d81e4cb 100644 --- a/core/src/main/scala/cats/syntax/apply.scala +++ b/core/src/main/scala/cats/syntax/apply.scala @@ -9,4 +9,36 @@ trait ApplySyntax extends TupleSemigroupalSyntax { val self = fa val typeClassInstance = F } + + implicit final def catsSyntaxApplyOps[F[_], A](fa: F[A]): ApplyOps[F, A] = + new ApplyOps(fa) + + implicit final def catsSyntaxApplyApOps[F[_], A, B](ff: F[A => B]): ApplyApOps[F, A, B] = + new ApplyApOps(ff) +} + +final class ApplyOps[F[_], A](val fa: F[A]) extends AnyVal { + /** Alias for [[*>]]. */ + @deprecated("Use *> or apR instead.", "1.0.0-RC2") + @inline def followedBy[B](fb: F[B])(implicit F: Apply[F]): F[B] = + F.apR(fa)(fb) + + /** Alias for [[<*]]. */ + @deprecated("Use <* or apL instead.", "1.0.0-RC2") + @inline def forEffect[B](fb: F[B])(implicit F: Apply[F]): F[A] = + F.apL(fa)(fb) + + /** Alias for [[Applicative.apR]]. */ + @inline def *>[B](fb: F[B])(implicit F: Apply[F]): F[B] = + F.apR(fa)(fb) + + /** Alias for [[Applicative.apL]]. */ + @inline def <*[B](fb: F[B])(implicit F: Apply[F]): F[A] = + F.apL(fa)(fb) +} + +final class ApplyApOps[F[_], A, B](val ff: F[A => B]) extends AnyVal { + /** Alias for [[Applicative.ap]]. */ + @inline def <*>(fa: F[A])(implicit F: Apply[F]): F[B] = + F.ap(ff)(fa) } diff --git a/core/src/main/scala/cats/syntax/flatMap.scala b/core/src/main/scala/cats/syntax/flatMap.scala index e3c8f14a5e..4391d7cbe0 100644 --- a/core/src/main/scala/cats/syntax/flatMap.scala +++ b/core/src/main/scala/cats/syntax/flatMap.scala @@ -33,7 +33,7 @@ final class FlatMapOps[F[_], A](val fa: F[A]) extends AnyVal { def >>[B](fb: => F[B])(implicit F: FlatMap[F]): F[B] = F.flatMap(fa)(_ => fb) @deprecated("Use <* instead", "1.0.0-RC1") - def <<[B](fb: F[B])(implicit F: FlatMap[F]): F[A] = F.forEffect(fa)(fb) + def <<[B](fb: F[B])(implicit F: FlatMap[F]): F[A] = F.apL(fa)(fb) } final class FlattenOps[F[_], A](val ffa: F[F[A]]) extends AnyVal { diff --git a/laws/src/main/scala/cats/laws/ApplyLaws.scala b/laws/src/main/scala/cats/laws/ApplyLaws.scala index a2543cc036..f028978b74 100644 --- a/laws/src/main/scala/cats/laws/ApplyLaws.scala +++ b/laws/src/main/scala/cats/laws/ApplyLaws.scala @@ -19,13 +19,13 @@ trait ApplyLaws[F[_]] extends FunctorLaws[F] with SemigroupalLaws[F] { F.map(F.product(fa, fb)) { case (a, b) => f(a, b) } <-> F.map2(fa, fb)(f) def map2EvalConsistency[A, B, C](fa: F[A], fb: F[B], f: (A, B) => C): IsEq[F[C]] = - F.map2(fa, fb)(f) <-> (F.map2Eval(fa, Eval.now(fb))(f).value) + F.map2(fa, fb)(f) <-> F.map2Eval(fa, Eval.now(fb))(f).value def followedByConsistency[A, B](fa: F[A], fb: F[B]): IsEq[F[B]] = - F.followedBy(fa)(fb) <-> F.map2(fa, fb)((_, b) => b) + F.apR(fa)(fb) <-> F.map2(fa, fb)((_, b) => b) def forEffectConsistency[A, B](fa: F[A], fb: F[B]): IsEq[F[A]] = - F.forEffect(fa)(fb) <-> F.map2(fa, fb)((a, _) => a) + F.apL(fa)(fb) <-> F.map2(fa, fb)((a, _) => a) } object ApplyLaws { From 40bc6d3b828281d0dbe4992dcbde762141ea04e0 Mon Sep 17 00:00:00 2001 From: Jacob Barber Date: Fri, 8 Dec 2017 15:49:02 -0600 Subject: [PATCH 02/14] Fix compatibility problem I introduced when I moved *> and <* --- core/src/main/scala/cats/Apply.scala | 15 ++++++++++++++- core/src/main/scala/cats/syntax/apply.scala | 21 ++------------------- 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/core/src/main/scala/cats/Apply.scala b/core/src/main/scala/cats/Apply.scala index 0679206067..69824e9304 100644 --- a/core/src/main/scala/cats/Apply.scala +++ b/core/src/main/scala/cats/Apply.scala @@ -1,6 +1,7 @@ package cats -import simulacrum.{typeclass, noop} +import simulacrum.typeclass +import simulacrum.noop /** * Weaker version of Applicative[F]; has apply but not pure. @@ -27,6 +28,18 @@ trait Apply[F[_]] extends Functor[F] with Semigroupal[F] with ApplyArityFunction override def product[A, B](fa: F[A], fb: F[B]): F[(A, B)] = ap(map(fa)(a => (b: B) => (a, b)))(fb) + /** Alias for [[ap]]. */ + @inline final def <*>[A, B](ff: F[A => B])(fa: F[A]): F[B] = + ap(ff)(fa) + + /** Alias for [[apR]]. */ + @inline final def *>[A, B](fa: F[A])(fb: F[B]): F[B] = + apR(fa)(fb) + + /** Alias for [[apL]]. */ + @inline final def <*[A, B](fa: F[A])(fb: F[B]): F[A] = + apL(fa)(fb) + /** Alias for [[apR]]. */ @deprecated("Use *> or apR instead.", "1.0.0-RC2") @noop @inline final def followedBy[A, B](fa: F[A])(fb: F[B]): F[B] = diff --git a/core/src/main/scala/cats/syntax/apply.scala b/core/src/main/scala/cats/syntax/apply.scala index 3e2d81e4cb..145c089743 100644 --- a/core/src/main/scala/cats/syntax/apply.scala +++ b/core/src/main/scala/cats/syntax/apply.scala @@ -12,33 +12,16 @@ trait ApplySyntax extends TupleSemigroupalSyntax { implicit final def catsSyntaxApplyOps[F[_], A](fa: F[A]): ApplyOps[F, A] = new ApplyOps(fa) - - implicit final def catsSyntaxApplyApOps[F[_], A, B](ff: F[A => B]): ApplyApOps[F, A, B] = - new ApplyApOps(ff) } final class ApplyOps[F[_], A](val fa: F[A]) extends AnyVal { - /** Alias for [[*>]]. */ + /** Alias for [[Apply.apR]]. */ @deprecated("Use *> or apR instead.", "1.0.0-RC2") @inline def followedBy[B](fb: F[B])(implicit F: Apply[F]): F[B] = F.apR(fa)(fb) - /** Alias for [[<*]]. */ + /** Alias for [[Apply.apL]]. */ @deprecated("Use <* or apL instead.", "1.0.0-RC2") @inline def forEffect[B](fb: F[B])(implicit F: Apply[F]): F[A] = F.apL(fa)(fb) - - /** Alias for [[Applicative.apR]]. */ - @inline def *>[B](fb: F[B])(implicit F: Apply[F]): F[B] = - F.apR(fa)(fb) - - /** Alias for [[Applicative.apL]]. */ - @inline def <*[B](fb: F[B])(implicit F: Apply[F]): F[A] = - F.apL(fa)(fb) -} - -final class ApplyApOps[F[_], A, B](val ff: F[A => B]) extends AnyVal { - /** Alias for [[Applicative.ap]]. */ - @inline def <*>(fa: F[A])(implicit F: Apply[F]): F[B] = - F.ap(ff)(fa) } From 3ae37e8ac36d011537ee2411b9ba8320cacd4261 Mon Sep 17 00:00:00 2001 From: Jacob Barber Date: Fri, 8 Dec 2017 16:30:32 -0600 Subject: [PATCH 03/14] updated parFollwedBy/parForEffect/followedByEval/forEffectEval to use the new names. --- core/src/main/scala/cats/FlatMap.scala | 18 ++++++++++++------ core/src/main/scala/cats/Parallel.scala | 14 ++++++++++---- core/src/main/scala/cats/syntax/parallel.scala | 4 ++-- laws/src/main/scala/cats/laws/ApplyLaws.scala | 4 ++-- .../cats/laws/discipline/ApplyTests.scala | 4 ++-- 5 files changed, 28 insertions(+), 16 deletions(-) diff --git a/core/src/main/scala/cats/FlatMap.scala b/core/src/main/scala/cats/FlatMap.scala index 211c7c39dd..cca5cbd6d1 100644 --- a/core/src/main/scala/cats/FlatMap.scala +++ b/core/src/main/scala/cats/FlatMap.scala @@ -51,17 +51,20 @@ import simulacrum.typeclass * scala> import cats.implicits._ * scala> val fa: Option[Int] = Some(3) * scala> def fb: Option[String] = Some("foo") - * scala> fa.followedByEval(Eval.later(fb)) + * scala> fa.apREval(Eval.later(fb)) * res0: Option[String] = Some(foo) * }}} */ - def followedByEval[A, B](fa: F[A])(fb: Eval[F[B]]): F[B] = flatMap(fa)(_ => fb.value) + def apREval[A, B](fa: F[A])(fb: Eval[F[B]]): F[B] = flatMap(fa)(_ => fb.value) + + @deprecated("Use apREval instead.", "1.0.0-RC2") + def followedByEval[A, B](fa: F[A])(fb: Eval[F[B]]): F[B] = apREval(fa)(fb) /** * Sequentially compose two actions, discarding any value produced by the second. This variant of - * [[forEffect]] also lets you define the evaluation strategy of the second action. For instance + * [[apL]] also lets you define the evaluation strategy of the second action. For instance * you can evaluate it only ''after'' the first action has finished: * * {{{ @@ -70,15 +73,18 @@ import simulacrum.typeclass * scala> var count = 0 * scala> val fa: Option[Int] = Some(3) * scala> def fb: Option[Unit] = Some(count += 1) - * scala> fa.forEffectEval(Eval.later(fb)) + * scala> fa.apLEval(Eval.later(fb)) * res0: Option[Int] = Some(3) * scala> assert(count == 1) - * scala> none[Int].forEffectEval(Eval.later(fb)) + * scala> none[Int].apLEval(Eval.later(fb)) * res1: Option[Int] = None * scala> assert(count == 1) * }}} */ - def forEffectEval[A, B](fa: F[A])(fb: Eval[F[B]]): F[A] = flatMap(fa)(a => map(fb.value)(_ => a)) + def apLEval[A, B](fa: F[A])(fb: Eval[F[B]]): F[A] = flatMap(fa)(a => map(fb.value)(_ => a)) + + @deprecated("Use apLEval instead.", "1.0.0-RC2") + def forEffectEval[A, B](fa: F[A])(fb: Eval[F[B]]): F[A] = apLEval(fa)(fb) override def ap[A, B](ff: F[A => B])(fa: F[A]): F[B] = flatMap(ff)(f => map(fa)(f)) diff --git a/core/src/main/scala/cats/Parallel.scala b/core/src/main/scala/cats/Parallel.scala index 947a90824f..1bfe2d268a 100644 --- a/core/src/main/scala/cats/Parallel.scala +++ b/core/src/main/scala/cats/Parallel.scala @@ -29,20 +29,26 @@ trait NonEmptyParallel[M[_], F[_]] extends Serializable { /** - * Like `Apply[F].followedBy`, but uses the apply instance + * Like `Apply[F].apR`, but uses the apply instance * corresponding to the Parallel instance instead. */ - def parFollowedBy[A, B](ma: M[A])(mb: M[B]): M[B] = + def parApR[A, B](ma: M[A])(mb: M[B]): M[B] = Parallel.parMap2(ma, mb)((_, b) => b)(this) + @deprecated("Use parApR instead.", "1.0.0-RC2") + @inline def parFollowedBy[A, B](ma: M[A])(mb: M[B]): M[B] = parApR(ma, mb) + /** - * Like `Apply[F].forEffect`, but uses the apply instance + * Like `Apply[F].apL`, but uses the apply instance * corresponding to the Parallel instance instead. */ - def parForEffect[A, B](ma: M[A])(mb: M[B]): M[A] = + def parApL[A, B](ma: M[A])(mb: M[B]): M[A] = Parallel.parMap2(ma, mb)((a, _) => a)(this) + @deprecated("Use parApR instead.", "1.0.0-RC2") + @inline def parForEffect[A, B](ma: M[A])(mb: M[B]): M[A] = parApL(ma)(mb) + } /** diff --git a/core/src/main/scala/cats/syntax/parallel.scala b/core/src/main/scala/cats/syntax/parallel.scala index 084d50423c..e1fc8acba8 100644 --- a/core/src/main/scala/cats/syntax/parallel.scala +++ b/core/src/main/scala/cats/syntax/parallel.scala @@ -32,9 +32,9 @@ final class ParallelSequenceOps[T[_], M[_], A](val tma: T[M[A]]) extends AnyVal final class ParallelApOps[M[_], A](val ma: M[A]) extends AnyVal { def &>[F[_], B](mb: M[B])(implicit P: Parallel[M, F]): M[B] = - P.parFollowedBy(ma)(mb) + P.parApR(ma)(mb) def <&[F[_], B](mb: M[B])(implicit P: Parallel[M, F]): M[A] = - P.parForEffect(ma)(mb) + P.parApL(ma)(mb) } diff --git a/laws/src/main/scala/cats/laws/ApplyLaws.scala b/laws/src/main/scala/cats/laws/ApplyLaws.scala index f028978b74..5b293ac82b 100644 --- a/laws/src/main/scala/cats/laws/ApplyLaws.scala +++ b/laws/src/main/scala/cats/laws/ApplyLaws.scala @@ -21,10 +21,10 @@ trait ApplyLaws[F[_]] extends FunctorLaws[F] with SemigroupalLaws[F] { def map2EvalConsistency[A, B, C](fa: F[A], fb: F[B], f: (A, B) => C): IsEq[F[C]] = F.map2(fa, fb)(f) <-> F.map2Eval(fa, Eval.now(fb))(f).value - def followedByConsistency[A, B](fa: F[A], fb: F[B]): IsEq[F[B]] = + def apRConsistency[A, B](fa: F[A], fb: F[B]): IsEq[F[B]] = F.apR(fa)(fb) <-> F.map2(fa, fb)((_, b) => b) - def forEffectConsistency[A, B](fa: F[A], fb: F[B]): IsEq[F[A]] = + def apLConsistency[A, B](fa: F[A], fb: F[B]): IsEq[F[A]] = F.apL(fa)(fb) <-> F.map2(fa, fb)((a, _) => a) } diff --git a/laws/src/main/scala/cats/laws/discipline/ApplyTests.scala b/laws/src/main/scala/cats/laws/discipline/ApplyTests.scala index 5b54e3f643..ede2db6b8b 100644 --- a/laws/src/main/scala/cats/laws/discipline/ApplyTests.scala +++ b/laws/src/main/scala/cats/laws/discipline/ApplyTests.scala @@ -30,8 +30,8 @@ trait ApplyTests[F[_]] extends FunctorTests[F] with SemigroupalTests[F] { "apply composition" -> forAll(laws.applyComposition[A, B, C] _), "map2/product-map consistency" -> forAll(laws.map2ProductConsistency[A, B, C] _), "map2/map2Eval consistency" -> forAll(laws.map2EvalConsistency[A, B, C] _), - "followedBy consistent map2" -> forAll(laws.followedByConsistency[A, C] _), - "forEffect consistent map2" -> forAll(laws.forEffectConsistency[A, C] _)) + "apR consistent map2" -> forAll(laws.apRConsistency[A, C] _), + "apL consistent map2" -> forAll(laws.apLConsistency[A, C] _)) } } From 265ffcaf8c80e618c8fc2e2fa2c6a6e027366bdb Mon Sep 17 00:00:00 2001 From: Jacob Barber Date: Fri, 8 Dec 2017 18:00:48 -0600 Subject: [PATCH 04/14] Create scalafix rules for PR 2083 --- scalafix/README.md | 2 ++ .../scala/fix/v1_0_0/RenameApplyApConst.scala | 34 +++++++++++++++++++ .../scala/fix/v1_0_0/RenameApplyApConst.scala | 34 +++++++++++++++++++ .../src/main/scala/fix/Cats_v1_0_0.scala | 17 ++++++++++ 4 files changed, 87 insertions(+) create mode 100644 scalafix/input/src/main/scala/fix/v1_0_0/RenameApplyApConst.scala create mode 100644 scalafix/output/src/main/scala/fix/v1_0_0/RenameApplyApConst.scala diff --git a/scalafix/README.md b/scalafix/README.md index 0dbbef53ee..d04901fcb7 100644 --- a/scalafix/README.md +++ b/scalafix/README.md @@ -36,6 +36,8 @@ sbt scalafix github:typelevel/cats/v1.0.0 - [x] Apply syntax on tuple (e.g. (x, y, z).map3(...)) was moved from cats.syntax.tuple._ to cats.syntax.apply._ and renamed to mapN, contramapN and imapN respectively. +- [x] Apply methods forEffect and followedBy were renamed to apL and apR respectively. This also effects forEffectEval, followedByEval, forEffectPar, and followedByPar. + - [x] Split is removed, and the method split is moved to Arrow. Note that only under CommutativeArrow does it guarantee the non-interference between the effects. see #1567 # WIP diff --git a/scalafix/input/src/main/scala/fix/v1_0_0/RenameApplyApConst.scala b/scalafix/input/src/main/scala/fix/v1_0_0/RenameApplyApConst.scala new file mode 100644 index 0000000000..ba44855d03 --- /dev/null +++ b/scalafix/input/src/main/scala/fix/v1_0_0/RenameApplyApConst.scala @@ -0,0 +1,34 @@ +/* +rule = "scala:fix.v1_0_0.RenameReducibleMethods" + */ +package fix +package to1_0_0 + + +object RenameApplyApConst { + import cats.{NonEmptyParallel, FlatMap, Apply, Eval} + import cats.data.NonEmptyList + import cats.data.NonEmptyList.ZipNonEmptyList + import cats.instances.all._ + import cats.syntax.all._ + + val l = NonEmptyList.of(5, 10) + val r = NonEmptyList.of(12, 13) + Apply[NonEmptyList].forEffect(l)(r) + Apply[NonEmptyList].followedBy(l)(r) + + l forEffect r + l followedBy r + + NonEmptyParallel[NonEmptyList, ZipNonEmptyList].parForEffect(l)(r) + NonEmptyParallel[NonEmptyList, ZipNonEmptyList].parFollowedBy(l)(r) + + l parForEffect r + l parFollowedBy r + + FlatMap[NonEmptyList].forEffectEval(l)(Eval.now(r)) + FlatMap[NonEmptyList].followedByEval(l)(Eval.now(r)) + + l forEffectEval Eval.now(r) + l followedByEval Eval.now(r) +} diff --git a/scalafix/output/src/main/scala/fix/v1_0_0/RenameApplyApConst.scala b/scalafix/output/src/main/scala/fix/v1_0_0/RenameApplyApConst.scala new file mode 100644 index 0000000000..c9c37ad2ab --- /dev/null +++ b/scalafix/output/src/main/scala/fix/v1_0_0/RenameApplyApConst.scala @@ -0,0 +1,34 @@ +/* +rule = "scala:fix.v1_0_0.RenameReducibleMethods" + */ +package fix +package to1_0_0 + + +object RenameApplyApConst { + import cats.{NonEmptyParallel, FlatMap, Apply, Eval} + import cats.data.NonEmptyList + import cats.data.NonEmptyList.ZipNonEmptyList + import cats.instances.all._ + import cats.syntax.all._ + + val l = NonEmptyList.of(5, 10) + val r = NonEmptyList.of(12, 13) + Apply[NonEmptyList].apL(l)(r) + Apply[NonEmptyList].apR(l)(r) + + l apL r + l apR r + + NonEmptyParallel[NonEmptyList, ZipNonEmptyList].parApL(l)(r) + NonEmptyParallel[NonEmptyList, ZipNonEmptyList].parApR(l)(r) + + // l parApL r + // l parApR r + + FlatMap[NonEmptyList].apLEval(l)(Eval.now(r)) + FlatMap[NonEmptyList].apREval(l)(Eval.now(r)) + + l apLEval Eval.now(r) + l apREval Eval.now(r) +} diff --git a/scalafix/rules/src/main/scala/fix/Cats_v1_0_0.scala b/scalafix/rules/src/main/scala/fix/Cats_v1_0_0.scala index 5b8cd59e17..b3bd103ebd 100644 --- a/scalafix/rules/src/main/scala/fix/Cats_v1_0_0.scala +++ b/scalafix/rules/src/main/scala/fix/Cats_v1_0_0.scala @@ -242,6 +242,23 @@ case class RenameTransformersLift(index: SemanticdbIndex) } +case class RenameApplyApConst(index: SemanticdbIndex) + extends SemanticRule(index, "RenameApplyApConst") { + + override def fix(ctx: RuleCtx): Patch = + ctx.replaceSymbols( + "_root_.cats.Apply.forEffect." -> "apL", + "_root_.cats.Apply.followedBy." -> "apR", + "_root_.cats.Apply.Ops.forEffect." -> "apL", + "_root_.cats.Apply.Ops.followedBy." -> "apR", + "_root_.cats.NonEmptyParallel.parForEffect." -> "parApL", + "_root_.cats.NonEmptyParallel.parFollowedBy." -> "parApR", + "_root_.cats.FlatMap.forEffectEval." -> "apLEval", + "_root_.cats.FlatMap.followedByEval." -> "apREval", + ) + +} + // ref: https://github.com/typelevel/cats/pull/1961 case class RenameCartesian(index: SemanticdbIndex) From 091fd3fc28c69d7a22760045556b8225fc78fd4a Mon Sep 17 00:00:00 2001 From: Jacob Barber Date: Fri, 8 Dec 2017 18:01:42 -0600 Subject: [PATCH 05/14] Minor fixes and adjustments to remain consistent with the existing api --- core/src/main/scala/cats/Apply.scala | 4 ++-- core/src/main/scala/cats/FlatMap.scala | 9 +++++---- core/src/main/scala/cats/Parallel.scala | 6 +++--- core/src/main/scala/cats/syntax/apply.scala | 4 ++-- core/src/main/scala/cats/syntax/flatMap.scala | 9 +++++++++ 5 files changed, 21 insertions(+), 11 deletions(-) diff --git a/core/src/main/scala/cats/Apply.scala b/core/src/main/scala/cats/Apply.scala index 69824e9304..4b0285bee8 100644 --- a/core/src/main/scala/cats/Apply.scala +++ b/core/src/main/scala/cats/Apply.scala @@ -41,12 +41,12 @@ trait Apply[F[_]] extends Functor[F] with Semigroupal[F] with ApplyArityFunction apL(fa)(fb) /** Alias for [[apR]]. */ - @deprecated("Use *> or apR instead.", "1.0.0-RC2") + @deprecated("Use *> or apR instead.", "1.0.0") @noop @inline final def followedBy[A, B](fa: F[A])(fb: F[B]): F[B] = apR(fa)(fb) /** Alias for [[apL]]. */ - @deprecated("Use <* or apL instead.", "1.0.0-RC2") + @deprecated("Use <* or apL instead.", "1.0.0") @noop @inline final def forEffect[A, B](fa: F[A])(fb: F[B]): F[A] = apL(fa)(fb) diff --git a/core/src/main/scala/cats/FlatMap.scala b/core/src/main/scala/cats/FlatMap.scala index cca5cbd6d1..a3357b4ff4 100644 --- a/core/src/main/scala/cats/FlatMap.scala +++ b/core/src/main/scala/cats/FlatMap.scala @@ -1,6 +1,7 @@ package cats import simulacrum.typeclass +import simulacrum.noop /** * FlatMap type class gives us flatMap, which allows us to have a value @@ -57,8 +58,8 @@ import simulacrum.typeclass */ def apREval[A, B](fa: F[A])(fb: Eval[F[B]]): F[B] = flatMap(fa)(_ => fb.value) - @deprecated("Use apREval instead.", "1.0.0-RC2") - def followedByEval[A, B](fa: F[A])(fb: Eval[F[B]]): F[B] = apREval(fa)(fb) + @deprecated("Use apREval instead.", "1.0.0") + @noop def followedByEval[A, B](fa: F[A])(fb: Eval[F[B]]): F[B] = apREval(fa)(fb) @@ -83,8 +84,8 @@ import simulacrum.typeclass */ def apLEval[A, B](fa: F[A])(fb: Eval[F[B]]): F[A] = flatMap(fa)(a => map(fb.value)(_ => a)) - @deprecated("Use apLEval instead.", "1.0.0-RC2") - def forEffectEval[A, B](fa: F[A])(fb: Eval[F[B]]): F[A] = apLEval(fa)(fb) + @deprecated("Use apLEval instead.", "1.0.0") + @noop def forEffectEval[A, B](fa: F[A])(fb: Eval[F[B]]): F[A] = apLEval(fa)(fb) override def ap[A, B](ff: F[A => B])(fa: F[A]): F[B] = flatMap(ff)(f => map(fa)(f)) diff --git a/core/src/main/scala/cats/Parallel.scala b/core/src/main/scala/cats/Parallel.scala index 1bfe2d268a..dfac6fca59 100644 --- a/core/src/main/scala/cats/Parallel.scala +++ b/core/src/main/scala/cats/Parallel.scala @@ -35,8 +35,8 @@ trait NonEmptyParallel[M[_], F[_]] extends Serializable { def parApR[A, B](ma: M[A])(mb: M[B]): M[B] = Parallel.parMap2(ma, mb)((_, b) => b)(this) - @deprecated("Use parApR instead.", "1.0.0-RC2") - @inline def parFollowedBy[A, B](ma: M[A])(mb: M[B]): M[B] = parApR(ma, mb) + @deprecated("Use parApR instead.", "1.0.0") + @inline def parFollowedBy[A, B](ma: M[A])(mb: M[B]): M[B] = parApR(ma)(mb) /** @@ -46,7 +46,7 @@ trait NonEmptyParallel[M[_], F[_]] extends Serializable { def parApL[A, B](ma: M[A])(mb: M[B]): M[A] = Parallel.parMap2(ma, mb)((a, _) => a)(this) - @deprecated("Use parApR instead.", "1.0.0-RC2") + @deprecated("Use parApR instead.", "1.0.0") @inline def parForEffect[A, B](ma: M[A])(mb: M[B]): M[A] = parApL(ma)(mb) } diff --git a/core/src/main/scala/cats/syntax/apply.scala b/core/src/main/scala/cats/syntax/apply.scala index 145c089743..b4900bc554 100644 --- a/core/src/main/scala/cats/syntax/apply.scala +++ b/core/src/main/scala/cats/syntax/apply.scala @@ -16,12 +16,12 @@ trait ApplySyntax extends TupleSemigroupalSyntax { final class ApplyOps[F[_], A](val fa: F[A]) extends AnyVal { /** Alias for [[Apply.apR]]. */ - @deprecated("Use *> or apR instead.", "1.0.0-RC2") + @deprecated("Use *> or apR instead.", "1.0.0") @inline def followedBy[B](fb: F[B])(implicit F: Apply[F]): F[B] = F.apR(fa)(fb) /** Alias for [[Apply.apL]]. */ - @deprecated("Use <* or apL instead.", "1.0.0-RC2") + @deprecated("Use <* or apL instead.", "1.0.0") @inline def forEffect[B](fb: F[B])(implicit F: Apply[F]): F[A] = F.apL(fa)(fb) } diff --git a/core/src/main/scala/cats/syntax/flatMap.scala b/core/src/main/scala/cats/syntax/flatMap.scala index 4391d7cbe0..1d578299d6 100644 --- a/core/src/main/scala/cats/syntax/flatMap.scala +++ b/core/src/main/scala/cats/syntax/flatMap.scala @@ -34,6 +34,15 @@ final class FlatMapOps[F[_], A](val fa: F[A]) extends AnyVal { @deprecated("Use <* instead", "1.0.0-RC1") def <<[B](fb: F[B])(implicit F: FlatMap[F]): F[A] = F.apL(fa)(fb) + + + @deprecated("Use apREval instead.", "1.0.0") + def followedByEval[B](fb: Eval[F[B]])(implicit F: FlatMap[F]): F[B] = + F.apREval(fa)(fb) + + @deprecated("Use apLEval instead.", "1.0.0") + def forEffectEval[B](fb: Eval[F[B]])(implicit F: FlatMap[F]): F[A] = + F.apLEval(fa)(fb) } final class FlattenOps[F[_], A](val ffa: F[F[A]]) extends AnyVal { From 171538b7c1a02acafec75ca50989d2f513127847 Mon Sep 17 00:00:00 2001 From: Jacob Barber Date: Sat, 9 Dec 2017 19:10:17 -0600 Subject: [PATCH 06/14] Un-comment the parApL/R tests. --- .../output/src/main/scala/fix/v1_0_0/RenameApplyApConst.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scalafix/output/src/main/scala/fix/v1_0_0/RenameApplyApConst.scala b/scalafix/output/src/main/scala/fix/v1_0_0/RenameApplyApConst.scala index c9c37ad2ab..9fb7a9a353 100644 --- a/scalafix/output/src/main/scala/fix/v1_0_0/RenameApplyApConst.scala +++ b/scalafix/output/src/main/scala/fix/v1_0_0/RenameApplyApConst.scala @@ -23,8 +23,8 @@ object RenameApplyApConst { NonEmptyParallel[NonEmptyList, ZipNonEmptyList].parApL(l)(r) NonEmptyParallel[NonEmptyList, ZipNonEmptyList].parApR(l)(r) - // l parApL r - // l parApR r + l parApL r + l parApR r FlatMap[NonEmptyList].apLEval(l)(Eval.now(r)) FlatMap[NonEmptyList].apREval(l)(Eval.now(r)) From 5f6a0bb1fa7221cd90a9c7d7611ed0729d4e6700 Mon Sep 17 00:00:00 2001 From: Jacoby6000 Date: Sun, 10 Dec 2017 14:01:02 -0600 Subject: [PATCH 07/14] Remove scalafix tests for apL/apR --- .../scala/fix/v1_0_0/RenameApplyApConst.scala | 34 ------------------- .../scala/fix/v1_0_0/RenameApplyApConst.scala | 34 ------------------- 2 files changed, 68 deletions(-) delete mode 100644 scalafix/input/src/main/scala/fix/v1_0_0/RenameApplyApConst.scala delete mode 100644 scalafix/output/src/main/scala/fix/v1_0_0/RenameApplyApConst.scala diff --git a/scalafix/input/src/main/scala/fix/v1_0_0/RenameApplyApConst.scala b/scalafix/input/src/main/scala/fix/v1_0_0/RenameApplyApConst.scala deleted file mode 100644 index ba44855d03..0000000000 --- a/scalafix/input/src/main/scala/fix/v1_0_0/RenameApplyApConst.scala +++ /dev/null @@ -1,34 +0,0 @@ -/* -rule = "scala:fix.v1_0_0.RenameReducibleMethods" - */ -package fix -package to1_0_0 - - -object RenameApplyApConst { - import cats.{NonEmptyParallel, FlatMap, Apply, Eval} - import cats.data.NonEmptyList - import cats.data.NonEmptyList.ZipNonEmptyList - import cats.instances.all._ - import cats.syntax.all._ - - val l = NonEmptyList.of(5, 10) - val r = NonEmptyList.of(12, 13) - Apply[NonEmptyList].forEffect(l)(r) - Apply[NonEmptyList].followedBy(l)(r) - - l forEffect r - l followedBy r - - NonEmptyParallel[NonEmptyList, ZipNonEmptyList].parForEffect(l)(r) - NonEmptyParallel[NonEmptyList, ZipNonEmptyList].parFollowedBy(l)(r) - - l parForEffect r - l parFollowedBy r - - FlatMap[NonEmptyList].forEffectEval(l)(Eval.now(r)) - FlatMap[NonEmptyList].followedByEval(l)(Eval.now(r)) - - l forEffectEval Eval.now(r) - l followedByEval Eval.now(r) -} diff --git a/scalafix/output/src/main/scala/fix/v1_0_0/RenameApplyApConst.scala b/scalafix/output/src/main/scala/fix/v1_0_0/RenameApplyApConst.scala deleted file mode 100644 index 9fb7a9a353..0000000000 --- a/scalafix/output/src/main/scala/fix/v1_0_0/RenameApplyApConst.scala +++ /dev/null @@ -1,34 +0,0 @@ -/* -rule = "scala:fix.v1_0_0.RenameReducibleMethods" - */ -package fix -package to1_0_0 - - -object RenameApplyApConst { - import cats.{NonEmptyParallel, FlatMap, Apply, Eval} - import cats.data.NonEmptyList - import cats.data.NonEmptyList.ZipNonEmptyList - import cats.instances.all._ - import cats.syntax.all._ - - val l = NonEmptyList.of(5, 10) - val r = NonEmptyList.of(12, 13) - Apply[NonEmptyList].apL(l)(r) - Apply[NonEmptyList].apR(l)(r) - - l apL r - l apR r - - NonEmptyParallel[NonEmptyList, ZipNonEmptyList].parApL(l)(r) - NonEmptyParallel[NonEmptyList, ZipNonEmptyList].parApR(l)(r) - - l parApL r - l parApR r - - FlatMap[NonEmptyList].apLEval(l)(Eval.now(r)) - FlatMap[NonEmptyList].apREval(l)(Eval.now(r)) - - l apLEval Eval.now(r) - l apREval Eval.now(r) -} From 59438754429ca9a3e02e61815b940ce3e79f3aab Mon Sep 17 00:00:00 2001 From: "Kai(luo) Wang" Date: Wed, 13 Dec 2017 10:27:03 -0500 Subject: [PATCH 08/14] added Mima exceptions --- build.sbt | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index c16c1803c2..541e4e4e40 100644 --- a/build.sbt +++ b/build.sbt @@ -323,7 +323,38 @@ def mimaSettings(moduleName: String) = Seq( exclude[ReversedMissingMethodProblem]("cats.MonadError.rethrow"), exclude[ReversedMissingMethodProblem]("cats.syntax.MonadErrorSyntax.catsSyntaxMonadErrorRethrow"), exclude[DirectMissingMethodProblem]("cats.data.CokleisliArrow.id"), - exclude[IncompatibleResultTypeProblem]("cats.data.CokleisliArrow.id") + exclude[IncompatibleResultTypeProblem]("cats.data.CokleisliArrow.id"), + exclude[DirectMissingMethodProblem]("cats.Apply#Ops.followedBy"), + exclude[DirectMissingMethodProblem]("cats.Apply#Ops.forEffect"), + exclude[ReversedMissingMethodProblem]("cats.Apply#Ops.<*>"), + exclude[ReversedMissingMethodProblem]("cats.Apply#Ops.apR"), + exclude[ReversedMissingMethodProblem]("cats.Apply#Ops.apL"), + exclude[ReversedMissingMethodProblem]("cats.Apply.<*>"), + exclude[ReversedMissingMethodProblem]("cats.Apply.apR"), + exclude[ReversedMissingMethodProblem]("cats.Apply.apL"), + exclude[ReversedMissingMethodProblem]("cats.FlatMap.apREval"), + exclude[ReversedMissingMethodProblem]("cats.FlatMap.apLEval"), + exclude[DirectMissingMethodProblem]("cats.FlatMap#Ops.forEffectEval"), + exclude[DirectMissingMethodProblem]("cats.FlatMap#Ops.followedByEval"), + exclude[ReversedMissingMethodProblem]("cats.FlatMap#Ops.apREval"), + exclude[ReversedMissingMethodProblem]("cats.FlatMap#Ops.apLEval"), + exclude[ReversedMissingMethodProblem]("cats.NonEmptyParallel.parApR"), + exclude[ReversedMissingMethodProblem]("cats.NonEmptyParallel.parApL"), + exclude[ReversedMissingMethodProblem]("cats.syntax.ApplySyntax.catsSyntaxApplyOps"), + exclude[FinalMethodProblem]("cats.data.IndexedStateTMonad.followedBy"), + exclude[FinalMethodProblem]("cats.data.IndexedStateTMonad.forEffect"), + exclude[FinalMethodProblem]("cats.data.RWSTMonad.followedBy"), + exclude[FinalMethodProblem]("cats.data.RWSTMonad.forEffect"), + exclude[FinalMethodProblem]("cats.data.CokleisliMonad.followedBy"), + exclude[FinalMethodProblem]("cats.data.CokleisliMonad.forEffect"), + exclude[FinalMethodProblem]("cats.data.NestedApplicativeError.followedBy"), + exclude[FinalMethodProblem]("cats.data.NestedApplicativeError.forEffect"), + exclude[FinalMethodProblem]("cats.data.ValidatedApplicative.followedBy"), + exclude[FinalMethodProblem]("cats.data.ValidatedApplicative.forEffect"), + exclude[FinalMethodProblem]("cats.data.RWSTAlternative.followedBy"), + exclude[FinalMethodProblem]("cats.data.RWSTAlternative.forEffect"), + exclude[IncompatibleMethTypeProblem]("cats.instances.FlatMapTuple2.followedBy"), + exclude[IncompatibleMethTypeProblem]("cats.instances.FlatMapTuple2.forEffect") ) } ) From b9112c1fc3bd03400885215919845e68e48e3d4a Mon Sep 17 00:00:00 2001 From: LukaJCB Date: Thu, 14 Dec 2017 11:18:09 +0000 Subject: [PATCH 09/14] Update FAQ symbols --- docs/src/main/tut/faq.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/src/main/tut/faq.md b/docs/src/main/tut/faq.md index b6d41a9e3c..dd670666cb 100644 --- a/docs/src/main/tut/faq.md +++ b/docs/src/main/tut/faq.md @@ -213,12 +213,12 @@ All other symbols can be imported with `import cats.implicits._` | Symbol | Name | Nickname | Type Class | Signature | | -------------------------------- | -------------------------| ---------------- | ----------------------- | --------------------------------------------------------------------| -| `fa *> fb` | followed by | | `Apply[F[_]]` | `followedBy(fa: F[A])(fb: F[B]): F[B]` | -| `fa <* fb` | for effect | | `Apply[F[_]]` | `forEffect(fa: F[A])(fb: F[B]): F[A]` | +| `fa *> fb` | ap right | | `Apply[F[_]]` | `apR(fa: F[A])(fb: F[B]): F[B]` | +| `fa <* fb` | ap left | | `Apply[F[_]]` | `apL(fa: F[A])(fb: F[B]): F[A]` | | `x === y` | equals | | `Eq[A]` | `eqv(x: A, y: A): Boolean` | | `x =!= y` | not equals | | `Eq[A]` | `neqv(x: A, y: A): Boolean` | | `fa >>= f` | flatMap | | `FlatMap[F[_]]` | `flatMap(fa: F[A])(f: A => F[B]): F[B]` | -| `fa >> fb` | followed by | | `FlatMap[F[_]]` | `followedBy(fa: F[A])(fb: F[B]): F[B]` | +| `fa >> fb` | followed by | | `FlatMap[F[_]]` | `followedBy(fa: F[A])(fb: => F[B]): F[B]` | | x |-| y | remove | | `Group[A]` | `remove(x: A, y: A): A` | | `x > y` | greater than | | `PartialOrder[A]` | `gt(x: A, y: A): Boolean` | | `x >= y` | greater than or equal | | `PartialOrder[A]` | `gteq(x: A, y: A): Boolean` | @@ -233,11 +233,11 @@ All other symbols can be imported with `import cats.implicits._` | `F ~> G` | natural transformation | | `FunctionK[F[_], G[_]]` | `FunctionK` alias | | `F :<: G` | injectK | | `InjectK[F[_], G[_]]` | `InjectK` alias | | `F :≺: G` | injectK | | `InjectK[F[_], G[_]]` | `InjectK` alias | -| `fa &> fb` | parallel followed by | | `Parallel[M[_], F[_]]` | `parFollowedBy[A, B](ma: M[A])(mb: M[B]): M[B]` | -| `fa <& fb` | parallel for effect | | `Parallel[M[_], F[_]]` | `parForEffect[A, B](ma: M[A])(mb: M[B]): M[A]` | +| `fa &> fb` | parallel ap right | | `Parallel[M[_], F[_]]` | `parApR[A, B](ma: M[A])(mb: M[B]): M[B]` | +| `fa <& fb` | parallel ap left | | `Parallel[M[_], F[_]]` | `parApL[A, B](ma: M[A])(mb: M[B]): M[A]` | | `⊥` | bottom | | N/A | `Nothing` | | `⊤` | top | | N/A | `Any` | -| `fa << fb` (Deprecated) | for effect | | `FlatMap[F[_]]` | `forEffect(fa: F[A])(fb: F[B]): F[A]` | +| `fa << fb` (Deprecated) | ap left | | `FlatMap[F[_]]` | `apL(fa: F[A])(fb: F[B]): F[A]` | ## How can I test instances against their type classes' laws? From eb7edd902efdc35d25cb6a94de8ecaa6dbd856e1 Mon Sep 17 00:00:00 2001 From: Jacob Barber Date: Thu, 14 Dec 2017 21:18:38 -0600 Subject: [PATCH 10/14] Update deprecations, method name --- core/src/main/scala/cats/Apply.scala | 29 ++++++++++--------- core/src/main/scala/cats/FlatMap.scala | 22 +++++++------- core/src/main/scala/cats/Parallel.scala | 16 +++++----- .../src/main/scala/cats/instances/tuple.scala | 4 +-- core/src/main/scala/cats/syntax/apply.scala | 12 ++++---- core/src/main/scala/cats/syntax/flatMap.scala | 10 +++---- .../src/main/scala/cats/syntax/parallel.scala | 4 +-- laws/src/main/scala/cats/laws/ApplyLaws.scala | 4 +-- 8 files changed, 51 insertions(+), 50 deletions(-) diff --git a/core/src/main/scala/cats/Apply.scala b/core/src/main/scala/cats/Apply.scala index 4b0285bee8..3462b6cbe1 100644 --- a/core/src/main/scala/cats/Apply.scala +++ b/core/src/main/scala/cats/Apply.scala @@ -18,42 +18,43 @@ trait Apply[F[_]] extends Functor[F] with Semigroupal[F] with ApplyArityFunction def ap[A, B](ff: F[A => B])(fa: F[A]): F[B] /** Compose two actions, discarding any value produced by the first. */ - def apR[A, B](fa: F[A])(fb: F[B]): F[B] = + def productR[A, B](fa: F[A])(fb: F[B]): F[B] = map2(fa, fb)((_, b) => b) /** Compose two actions, discarding any value produced by the second. */ - def apL[A, B](fa: F[A])(fb: F[B]): F[A] = + def productL[A, B](fa: F[A])(fb: F[B]): F[A] = map2(fa, fb)((a, _) => a) override def product[A, B](fa: F[A], fb: F[B]): F[(A, B)] = - ap(map(fa)(a => (b: B) => (a, b)))(fb) + map2(fa, fb)((_, _)) /** Alias for [[ap]]. */ @inline final def <*>[A, B](ff: F[A => B])(fa: F[A]): F[B] = ap(ff)(fa) - /** Alias for [[apR]]. */ + /** Alias for [[productR]]. */ @inline final def *>[A, B](fa: F[A])(fb: F[B]): F[B] = - apR(fa)(fb) + productR(fa)(fb) - /** Alias for [[apL]]. */ + /** Alias for [[productL]]. */ @inline final def <*[A, B](fa: F[A])(fb: F[B]): F[A] = - apL(fa)(fb) + productL(fa)(fb) - /** Alias for [[apR]]. */ - @deprecated("Use *> or apR instead.", "1.0.0") + /** Alias for [[productR]]. */ + @deprecated("Use *> or apR instead.", "1.0.0-RC2") @noop @inline final def followedBy[A, B](fa: F[A])(fb: F[B]): F[B] = - apR(fa)(fb) + productR(fa)(fb) - /** Alias for [[apL]]. */ - @deprecated("Use <* or apL instead.", "1.0.0") + /** Alias for [[productL]]. */ + @deprecated("Use <* or apL instead.", "1.0.0-RC2") @noop @inline final def forEffect[A, B](fa: F[A])(fb: F[B]): F[A] = - apL(fa)(fb) + productL(fa)(fb) /** * ap2 is a binary version of ap, defined in terms of ap. */ def ap2[A, B, Z](ff: F[(A, B) => Z])(fa: F[A], fb: F[B]): F[Z] = + map(product(fa, product(fb, ff))) { case (a, (b, f)) => f(a, b) } /** @@ -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) /** * Similar to [[map2]] but uses [[Eval]] to allow for laziness in the `F[B]` diff --git a/core/src/main/scala/cats/FlatMap.scala b/core/src/main/scala/cats/FlatMap.scala index a3357b4ff4..2aa4307dcf 100644 --- a/core/src/main/scala/cats/FlatMap.scala +++ b/core/src/main/scala/cats/FlatMap.scala @@ -44,7 +44,7 @@ import simulacrum.noop /** * Sequentially compose two actions, discarding any value produced by the first. This variant of - * [[apR]] also lets you define the evaluation strategy of the second action. For instance + * [[productR]] also lets you define the evaluation strategy of the second action. For instance * you can evaluate it only ''after'' the first action has finished: * * {{{ @@ -52,20 +52,20 @@ import simulacrum.noop * scala> import cats.implicits._ * scala> val fa: Option[Int] = Some(3) * scala> def fb: Option[String] = Some("foo") - * scala> fa.apREval(Eval.later(fb)) + * scala> fa.productREval(Eval.later(fb)) * res0: Option[String] = Some(foo) * }}} */ - def apREval[A, B](fa: F[A])(fb: Eval[F[B]]): F[B] = flatMap(fa)(_ => fb.value) + def productREval[A, B](fa: F[A])(fb: Eval[F[B]]): F[B] = flatMap(fa)(_ => fb.value) - @deprecated("Use apREval instead.", "1.0.0") - @noop def followedByEval[A, B](fa: F[A])(fb: Eval[F[B]]): F[B] = apREval(fa)(fb) + @deprecated("Use apREval instead.", "1.0.0-RC2") + @noop def followedByEval[A, B](fa: F[A])(fb: Eval[F[B]]): F[B] = productREval(fa)(fb) /** * Sequentially compose two actions, discarding any value produced by the second. This variant of - * [[apL]] also lets you define the evaluation strategy of the second action. For instance + * [[productL]] also lets you define the evaluation strategy of the second action. For instance * you can evaluate it only ''after'' the first action has finished: * * {{{ @@ -74,18 +74,18 @@ import simulacrum.noop * scala> var count = 0 * scala> val fa: Option[Int] = Some(3) * scala> def fb: Option[Unit] = Some(count += 1) - * scala> fa.apLEval(Eval.later(fb)) + * scala> fa.productLEval(Eval.later(fb)) * res0: Option[Int] = Some(3) * scala> assert(count == 1) - * scala> none[Int].apLEval(Eval.later(fb)) + * scala> none[Int].productLEval(Eval.later(fb)) * res1: Option[Int] = None * scala> assert(count == 1) * }}} */ - def apLEval[A, B](fa: F[A])(fb: Eval[F[B]]): F[A] = flatMap(fa)(a => map(fb.value)(_ => a)) + def productLEval[A, B](fa: F[A])(fb: Eval[F[B]]): F[A] = flatMap(fa)(a => map(fb.value)(_ => a)) - @deprecated("Use apLEval instead.", "1.0.0") - @noop def forEffectEval[A, B](fa: F[A])(fb: Eval[F[B]]): F[A] = apLEval(fa)(fb) + @deprecated("Use apLEval instead.", "1.0.0-RC2") + @noop def forEffectEval[A, B](fa: F[A])(fb: Eval[F[B]]): F[A] = productLEval(fa)(fb) override def ap[A, B](ff: F[A => B])(fa: F[A]): F[B] = flatMap(ff)(f => map(fa)(f)) diff --git a/core/src/main/scala/cats/Parallel.scala b/core/src/main/scala/cats/Parallel.scala index dfac6fca59..eea61e8085 100644 --- a/core/src/main/scala/cats/Parallel.scala +++ b/core/src/main/scala/cats/Parallel.scala @@ -29,25 +29,25 @@ trait NonEmptyParallel[M[_], F[_]] extends Serializable { /** - * Like `Apply[F].apR`, but uses the apply instance + * Like [[Apply.productR]], but uses the apply instance * corresponding to the Parallel instance instead. */ - def parApR[A, B](ma: M[A])(mb: M[B]): M[B] = + def parProductR[A, B](ma: M[A])(mb: M[B]): M[B] = Parallel.parMap2(ma, mb)((_, b) => b)(this) - @deprecated("Use parApR instead.", "1.0.0") - @inline def parFollowedBy[A, B](ma: M[A])(mb: M[B]): M[B] = parApR(ma)(mb) + @deprecated("Use parApR instead.", "1.0.0-RC2") + @inline def parFollowedBy[A, B](ma: M[A])(mb: M[B]): M[B] = parProductR(ma)(mb) /** - * Like `Apply[F].apL`, but uses the apply instance + * Like [[Apply.productL]], but uses the apply instance * corresponding to the Parallel instance instead. */ - def parApL[A, B](ma: M[A])(mb: M[B]): M[A] = + def parProductL[A, B](ma: M[A])(mb: M[B]): M[A] = Parallel.parMap2(ma, mb)((a, _) => a)(this) - @deprecated("Use parApR instead.", "1.0.0") - @inline def parForEffect[A, B](ma: M[A])(mb: M[B]): M[A] = parApL(ma)(mb) + @deprecated("Use parApR instead.", "1.0.0-RC2") + @inline def parForEffect[A, B](ma: M[A])(mb: M[B]): M[A] = parProductL(ma)(mb) } diff --git a/core/src/main/scala/cats/instances/tuple.scala b/core/src/main/scala/cats/instances/tuple.scala index 6c460201e5..2e8501a3f1 100644 --- a/core/src/main/scala/cats/instances/tuple.scala +++ b/core/src/main/scala/cats/instances/tuple.scala @@ -123,10 +123,10 @@ private[instances] class FlatMapTuple2[X](s: Semigroup[X]) extends FlatMap[(X, ? (x, xb._2) } - override def apR[A, B](a: (X, A))(b: (X, B)): (X, B) = + override def productR[A, B](a: (X, A))(b: (X, B)): (X, B) = (s.combine(a._1, b._1), b._2) - override def apL[A, B](a: (X, A))(b: (X, B)): (X, A) = + override def productL[A, B](a: (X, A))(b: (X, B)): (X, A) = (s.combine(a._1, b._1), a._2) override def mproduct[A, B](fa: (X, A))(f: A => (X, B)): (X, (A, B)) = { diff --git a/core/src/main/scala/cats/syntax/apply.scala b/core/src/main/scala/cats/syntax/apply.scala index b4900bc554..6d8daec464 100644 --- a/core/src/main/scala/cats/syntax/apply.scala +++ b/core/src/main/scala/cats/syntax/apply.scala @@ -15,13 +15,13 @@ trait ApplySyntax extends TupleSemigroupalSyntax { } final class ApplyOps[F[_], A](val fa: F[A]) extends AnyVal { - /** Alias for [[Apply.apR]]. */ - @deprecated("Use *> or apR instead.", "1.0.0") + /** Alias for [[Apply.productR]]. */ + @deprecated("Use *> or apR instead.", "1.0.0-RC2") @inline def followedBy[B](fb: F[B])(implicit F: Apply[F]): F[B] = - F.apR(fa)(fb) + F.productR(fa)(fb) - /** Alias for [[Apply.apL]]. */ - @deprecated("Use <* or apL instead.", "1.0.0") + /** Alias for [[Apply.productL]]. */ + @deprecated("Use <* or apL instead.", "1.0.0-RC2") @inline def forEffect[B](fb: F[B])(implicit F: Apply[F]): F[A] = - F.apL(fa)(fb) + F.productL(fa)(fb) } diff --git a/core/src/main/scala/cats/syntax/flatMap.scala b/core/src/main/scala/cats/syntax/flatMap.scala index 1d578299d6..b3b22e83a4 100644 --- a/core/src/main/scala/cats/syntax/flatMap.scala +++ b/core/src/main/scala/cats/syntax/flatMap.scala @@ -33,16 +33,16 @@ final class FlatMapOps[F[_], A](val fa: F[A]) extends AnyVal { def >>[B](fb: => F[B])(implicit F: FlatMap[F]): F[B] = F.flatMap(fa)(_ => fb) @deprecated("Use <* instead", "1.0.0-RC1") - def <<[B](fb: F[B])(implicit F: FlatMap[F]): F[A] = F.apL(fa)(fb) + def <<[B](fb: F[B])(implicit F: FlatMap[F]): F[A] = F.productL(fa)(fb) - @deprecated("Use apREval instead.", "1.0.0") + @deprecated("Use productREval instead.", "1.0.0-RC2") def followedByEval[B](fb: Eval[F[B]])(implicit F: FlatMap[F]): F[B] = - F.apREval(fa)(fb) + F.productREval(fa)(fb) - @deprecated("Use apLEval instead.", "1.0.0") + @deprecated("Use productLEval instead.", "1.0.0-RC2") def forEffectEval[B](fb: Eval[F[B]])(implicit F: FlatMap[F]): F[A] = - F.apLEval(fa)(fb) + F.productLEval(fa)(fb) } final class FlattenOps[F[_], A](val ffa: F[F[A]]) extends AnyVal { diff --git a/core/src/main/scala/cats/syntax/parallel.scala b/core/src/main/scala/cats/syntax/parallel.scala index e1fc8acba8..62be5e7915 100644 --- a/core/src/main/scala/cats/syntax/parallel.scala +++ b/core/src/main/scala/cats/syntax/parallel.scala @@ -32,9 +32,9 @@ final class ParallelSequenceOps[T[_], M[_], A](val tma: T[M[A]]) extends AnyVal final class ParallelApOps[M[_], A](val ma: M[A]) extends AnyVal { def &>[F[_], B](mb: M[B])(implicit P: Parallel[M, F]): M[B] = - P.parApR(ma)(mb) + P.parProductR(ma)(mb) def <&[F[_], B](mb: M[B])(implicit P: Parallel[M, F]): M[A] = - P.parApL(ma)(mb) + P.parProductL(ma)(mb) } diff --git a/laws/src/main/scala/cats/laws/ApplyLaws.scala b/laws/src/main/scala/cats/laws/ApplyLaws.scala index 5b293ac82b..a4f1175481 100644 --- a/laws/src/main/scala/cats/laws/ApplyLaws.scala +++ b/laws/src/main/scala/cats/laws/ApplyLaws.scala @@ -22,10 +22,10 @@ trait ApplyLaws[F[_]] extends FunctorLaws[F] with SemigroupalLaws[F] { F.map2(fa, fb)(f) <-> F.map2Eval(fa, Eval.now(fb))(f).value def apRConsistency[A, B](fa: F[A], fb: F[B]): IsEq[F[B]] = - F.apR(fa)(fb) <-> F.map2(fa, fb)((_, b) => b) + F.productR(fa)(fb) <-> F.map2(fa, fb)((_, b) => b) def apLConsistency[A, B](fa: F[A], fb: F[B]): IsEq[F[A]] = - F.apL(fa)(fb) <-> F.map2(fa, fb)((a, _) => a) + F.productL(fa)(fb) <-> F.map2(fa, fb)((a, _) => a) } object ApplyLaws { From 6dca0cc166c207ea569fb96fdf01cb3e8c981a0a Mon Sep 17 00:00:00 2001 From: Jacob Barber Date: Thu, 14 Dec 2017 22:30:57 -0600 Subject: [PATCH 11/14] Update doc with product(L/R) --- docs/src/main/tut/faq.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/src/main/tut/faq.md b/docs/src/main/tut/faq.md index b2b1bc1c54..e591d22544 100644 --- a/docs/src/main/tut/faq.md +++ b/docs/src/main/tut/faq.md @@ -214,8 +214,8 @@ All other symbols can be imported with `import cats.implicits._` | Symbol | Name | Nickname | Type Class | Signature | | -------------------------------- | -------------------------| ---------------- | ----------------------- | --------------------------------------------------------------------| -| `fa *> fb` | ap right | | `Apply[F[_]]` | `apR(fa: F[A])(fb: F[B]): F[B]` | -| `fa <* fb` | ap left | | `Apply[F[_]]` | `apL(fa: F[A])(fb: F[B]): F[A]` | +| `fa *> fb` | product right | | `Apply[F[_]]` | `productR(fa: F[A])(fb: F[B]): F[B]` | +| `fa <* fb` | product left | | `Apply[F[_]]` | `productL(fa: F[A])(fb: F[B]): F[A]` | | `x === y` | equals | | `Eq[A]` | `eqv(x: A, y: A): Boolean` | | `x =!= y` | not equals | | `Eq[A]` | `neqv(x: A, y: A): Boolean` | | `fa >>= f` | flatMap | | `FlatMap[F[_]]` | `flatMap(fa: F[A])(f: A => F[B]): F[B]` | @@ -234,11 +234,11 @@ All other symbols can be imported with `import cats.implicits._` | `F ~> G` | natural transformation | | `FunctionK[F[_], G[_]]` | `FunctionK` alias | | `F :<: G` | injectK | | `InjectK[F[_], G[_]]` | `InjectK` alias | | `F :≺: G` | injectK | | `InjectK[F[_], G[_]]` | `InjectK` alias | -| `fa &> fb` | parallel ap right | | `Parallel[M[_], F[_]]` | `parApR[A, B](ma: M[A])(mb: M[B]): M[B]` | -| `fa <& fb` | parallel ap left | | `Parallel[M[_], F[_]]` | `parApL[A, B](ma: M[A])(mb: M[B]): M[A]` | +| `fa &> fb` | parallel product right | | `Parallel[M[_], F[_]]` | `parProductR[A, B](ma: M[A])(mb: M[B]): M[B]` | +| `fa <& fb` | parallel product left | | `Parallel[M[_], F[_]]` | `parProductL[A, B](ma: M[A])(mb: M[B]): M[A]` | | `⊥` | bottom | | N/A | `Nothing` | | `⊤` | top | | N/A | `Any` | -| `fa << fb` (Deprecated) | ap left | | `FlatMap[F[_]]` | `apL(fa: F[A])(fb: F[B]): F[A]` | +| `fa << fb` (Deprecated) | product left | | `FlatMap[F[_]]` | `productL(fa: F[A])(fb: F[B]): F[A]` | ## How can I test instances against their type classes' laws? From 1ec6706eb4c01f60efd8ddb42fbeeb53d95b23a3 Mon Sep 17 00:00:00 2001 From: Jacob Barber Date: Thu, 14 Dec 2017 22:32:58 -0600 Subject: [PATCH 12/14] Update mima for product(L/R) --- build.sbt | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/build.sbt b/build.sbt index e941ae85ba..1d84ad3ad2 100644 --- a/build.sbt +++ b/build.sbt @@ -345,19 +345,19 @@ def mimaSettings(moduleName: String) = Seq( exclude[DirectMissingMethodProblem]("cats.Apply#Ops.followedBy"), exclude[DirectMissingMethodProblem]("cats.Apply#Ops.forEffect"), exclude[ReversedMissingMethodProblem]("cats.Apply#Ops.<*>"), - exclude[ReversedMissingMethodProblem]("cats.Apply#Ops.apR"), - exclude[ReversedMissingMethodProblem]("cats.Apply#Ops.apL"), + exclude[ReversedMissingMethodProblem]("cats.Apply#Ops.productR"), + exclude[ReversedMissingMethodProblem]("cats.Apply#Ops.productL"), exclude[ReversedMissingMethodProblem]("cats.Apply.<*>"), - exclude[ReversedMissingMethodProblem]("cats.Apply.apR"), - exclude[ReversedMissingMethodProblem]("cats.Apply.apL"), - exclude[ReversedMissingMethodProblem]("cats.FlatMap.apREval"), - exclude[ReversedMissingMethodProblem]("cats.FlatMap.apLEval"), + exclude[ReversedMissingMethodProblem]("cats.Apply.productR"), + exclude[ReversedMissingMethodProblem]("cats.Apply.productL"), + exclude[ReversedMissingMethodProblem]("cats.FlatMap.productREval"), + exclude[ReversedMissingMethodProblem]("cats.FlatMap.productLEval"), exclude[DirectMissingMethodProblem]("cats.FlatMap#Ops.forEffectEval"), exclude[DirectMissingMethodProblem]("cats.FlatMap#Ops.followedByEval"), - exclude[ReversedMissingMethodProblem]("cats.FlatMap#Ops.apREval"), - exclude[ReversedMissingMethodProblem]("cats.FlatMap#Ops.apLEval"), - exclude[ReversedMissingMethodProblem]("cats.NonEmptyParallel.parApR"), - exclude[ReversedMissingMethodProblem]("cats.NonEmptyParallel.parApL"), + exclude[ReversedMissingMethodProblem]("cats.FlatMap#Ops.productREval"), + exclude[ReversedMissingMethodProblem]("cats.FlatMap#Ops.productLEval"), + exclude[ReversedMissingMethodProblem]("cats.NonEmptyParallel.parProductR"), + exclude[ReversedMissingMethodProblem]("cats.NonEmptyParallel.parProductL"), exclude[ReversedMissingMethodProblem]("cats.syntax.ApplySyntax.catsSyntaxApplyOps"), exclude[FinalMethodProblem]("cats.data.IndexedStateTMonad.followedBy"), exclude[FinalMethodProblem]("cats.data.IndexedStateTMonad.forEffect"), From 278b36e6af0bda061094cb37b966dce31e0372a2 Mon Sep 17 00:00:00 2001 From: Jacob Barber Date: Fri, 15 Dec 2017 01:43:01 -0600 Subject: [PATCH 13/14] Remove accidental whitespace --- core/src/main/scala/cats/Apply.scala | 1 - 1 file changed, 1 deletion(-) diff --git a/core/src/main/scala/cats/Apply.scala b/core/src/main/scala/cats/Apply.scala index 3462b6cbe1..96cbb3ae10 100644 --- a/core/src/main/scala/cats/Apply.scala +++ b/core/src/main/scala/cats/Apply.scala @@ -54,7 +54,6 @@ trait Apply[F[_]] extends Functor[F] with Semigroupal[F] with ApplyArityFunction * ap2 is a binary version of ap, defined in terms of ap. */ def ap2[A, B, Z](ff: F[(A, B) => Z])(fa: F[A], fb: F[B]): F[Z] = - map(product(fa, product(fb, ff))) { case (a, (b, f)) => f(a, b) } /** From 0153f3df5bb538773fb6a3b0295b972e6e7e8e3d Mon Sep 17 00:00:00 2001 From: Jacob Barber Date: Fri, 15 Dec 2017 11:36:59 -0600 Subject: [PATCH 14/14] Undo changes I made to map2/product --- core/src/main/scala/cats/Apply.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/scala/cats/Apply.scala b/core/src/main/scala/cats/Apply.scala index 96cbb3ae10..f9673c156d 100644 --- a/core/src/main/scala/cats/Apply.scala +++ b/core/src/main/scala/cats/Apply.scala @@ -26,7 +26,7 @@ trait Apply[F[_]] extends Functor[F] with Semigroupal[F] with ApplyArityFunction map2(fa, fb)((a, _) => a) override def product[A, B](fa: F[A], fb: F[B]): F[(A, B)] = - map2(fa, fb)((_, _)) + ap(map(fa)(a => (b: B) => (a, b)))(fb) /** Alias for [[ap]]. */ @inline final def <*>[A, B](ff: F[A => B])(fa: F[A]): F[B] = @@ -62,7 +62,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] = - ap(map(fa)(a => (b: B) => f(a, b)))(fb) + map(product(fa, fb))(f.tupled) /** * Similar to [[map2]] but uses [[Eval]] to allow for laziness in the `F[B]`