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
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,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[DirectMissingMethodProblem]("cats.Apply#Ops.followedBy"),
exclude[DirectMissingMethodProblem]("cats.Apply#Ops.forEffect"),
exclude[ReversedMissingMethodProblem]("cats.Apply#Ops.<*>"),
exclude[ReversedMissingMethodProblem]("cats.Apply#Ops.productR"),
exclude[ReversedMissingMethodProblem]("cats.Apply#Ops.productL"),
exclude[ReversedMissingMethodProblem]("cats.Apply.<*>"),
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.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"),
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"),
exclude[IncompatibleResultTypeProblem]("cats.data.CokleisliArrow.id"),
exclude[UpdateForwarderBodyProblem]("cats.instances.Tuple2Instances1.catsStdMonadForTuple2"),
exclude[ReversedMissingMethodProblem]("cats.instances.Tuple2Instances1.catsStdCommutativeMonadForTuple2"),
Expand Down
39 changes: 27 additions & 12 deletions core/src/main/scala/cats/Apply.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cats

import simulacrum.typeclass
import simulacrum.noop

/**
* Weaker version of Applicative[F]; has apply but not pure.
Expand All @@ -16,24 +17,38 @@ 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 productR[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 productL[A, B](fa: F[A])(fb: F[B]): F[A] =
map2(fa, fb)((a, _) => a)

/** Alias for [[forEffect]]. */
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 [[productR]]. */
@inline final def *>[A, B](fa: F[A])(fb: F[B]): F[B] =
productR(fa)(fb)

/** Alias for [[productL]]. */
@inline final def <*[A, B](fa: F[A])(fb: F[B]): F[A] =
forEffect(fa)(fb)
productL(fa)(fb)

/** 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] =
productR(fa)(fb)

/** 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] =
productL(fa)(fb)

/**
* ap2 is a binary version of ap, defined in terms of ap.
Expand All @@ -47,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] =
map(product(fa, fb)) { case (a, b) => f(a, b) }
map(product(fa, fb))(f.tupled)

/**
* Similar to [[map2]] but uses [[Eval]] to allow for laziness in the `F[B]`
Expand Down
21 changes: 14 additions & 7 deletions core/src/main/scala/cats/FlatMap.scala
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -43,25 +44,28 @@ 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
* [[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:
*
* {{{
* scala> import cats.Eval
* 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.productREval(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 productREval[A, B](fa: F[A])(fb: Eval[F[B]]): F[B] = flatMap(fa)(_ => fb.value)

@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
* [[forEffect]] 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:
*
* {{{
Expand All @@ -70,15 +74,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.productLEval(Eval.later(fb))
* res0: Option[Int] = Some(3)
* scala> assert(count == 1)
* scala> none[Int].forEffectEval(Eval.later(fb))
* scala> none[Int].productLEval(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 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-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))
Expand Down
14 changes: 10 additions & 4 deletions core/src/main/scala/cats/Parallel.scala
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,26 @@ trait NonEmptyParallel[M[_], F[_]] extends Serializable {


/**
* Like `Apply[F].followedBy`, but uses the apply instance
* Like [[Apply.productR]], but uses the apply instance
* corresponding to the Parallel instance instead.
*/
def parFollowedBy[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-RC2")
@inline def parFollowedBy[A, B](ma: M[A])(mb: M[B]): M[B] = parProductR(ma)(mb)


/**
* Like `Apply[F].forEffect`, but uses the apply instance
* Like [[Apply.productL]], but uses the apply instance
* corresponding to the Parallel instance instead.
*/
def parForEffect[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-RC2")
@inline def parForEffect[A, B](ma: M[A])(mb: M[B]): M[A] = parProductL(ma)(mb)

}

/**
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/scala/cats/instances/tuple.scala
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,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 productR[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 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)) = {
Expand Down
15 changes: 15 additions & 0 deletions core/src/main/scala/cats/syntax/apply.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,19 @@ 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)
}

final class ApplyOps[F[_], A](val fa: F[A]) extends AnyVal {
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm, why is it that this new syntax is needed? Does simulacrum not generate syntax for deprecated methods?

Copy link
Contributor

Choose a reason for hiding this comment

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

Generate as deprecated?

Copy link
Contributor Author

@Jacoby6000 Jacoby6000 Dec 14, 2017

Choose a reason for hiding this comment

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

Simulacrum does generate the deprecated methods, which makes scalac complain since it references the original deprecated method.

/** 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.productR(fa)(fb)

/** 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.productL(fa)(fb)
}
11 changes: 10 additions & 1 deletion core/src/main/scala/cats/syntax/flatMap.scala
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +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.forEffect(fa)(fb)
def <<[B](fb: F[B])(implicit F: FlatMap[F]): F[A] = F.productL(fa)(fb)


@deprecated("Use productREval instead.", "1.0.0-RC2")
def followedByEval[B](fb: Eval[F[B]])(implicit F: FlatMap[F]): F[B] =
F.productREval(fa)(fb)

@deprecated("Use productLEval instead.", "1.0.0-RC2")
def forEffectEval[B](fb: Eval[F[B]])(implicit F: FlatMap[F]): F[A] =
F.productLEval(fa)(fb)
}

final class FlattenOps[F[_], A](val ffa: F[F[A]]) extends AnyVal {
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/scala/cats/syntax/parallel.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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.parProductR(ma)(mb)

def <&[F[_], B](mb: M[B])(implicit P: Parallel[M, F]): M[A] =
P.parForEffect(ma)(mb)
P.parProductL(ma)(mb)

}
Loading