diff --git a/core/src/main/scala/cats/Apply.scala b/core/src/main/scala/cats/Apply.scala
index e0255a5d85..0d28130263 100644
--- a/core/src/main/scala/cats/Apply.scala
+++ b/core/src/main/scala/cats/Apply.scala
@@ -19,6 +19,22 @@ trait Apply[F[_]] extends Functor[F] with Cartesian[F] with ApplyArityFunctions[
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] =
+ 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] =
+ map2(fa, fb)((a, _) => a)
+
+ /** Alias for [[forEffect]]. */
+ @inline final def <*[A, B](fa: F[A])(fb: F[B]): F[A] =
+ forEffect(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 46956300be..ae687ba01a 100644
--- a/core/src/main/scala/cats/FlatMap.scala
+++ b/core/src/main/scala/cats/FlatMap.scala
@@ -44,11 +44,7 @@ import simulacrum.typeclass
def flatten[A](ffa: F[F[A]]): F[A] =
flatMap(ffa)(fa => fa)
- /** Sequentially compose two actions, discarding any value produced by the first. */
- def followedBy[A, B](fa: F[A])(fb: F[B]): F[B] = flatMap(fa)(_ => fb)
- /** Alias for [[followedBy]]. */
- @inline final def >>[A, B](fa: F[A])(fb: F[B]): F[B] = followedBy(fa)(fb)
/**
* Sequentially compose two actions, discarding any value produced by the first. This variant of
@@ -66,11 +62,7 @@ import simulacrum.typeclass
*/
def followedByEval[A, B](fa: F[A])(fb: Eval[F[B]]): F[B] = flatMap(fa)(_ => fb.value)
- /** Sequentially compose two actions, discarding any value produced by the second. */
- def forEffect[A, B](fa: F[A])(fb: F[B]): F[A] = flatMap(fa)(a => map(fb)(_ => a))
- /** Alias for [[forEffect]]. */
- @inline final def <<[A, B](fa: F[A])(fb: F[B]): F[A] = forEffect(fa)(fb)
/**
* Sequentially compose two actions, discarding any value produced by the second. This variant of
diff --git a/core/src/main/scala/cats/syntax/cartesian.scala b/core/src/main/scala/cats/syntax/cartesian.scala
index e2cb025588..cd2a13b1dc 100644
--- a/core/src/main/scala/cats/syntax/cartesian.scala
+++ b/core/src/main/scala/cats/syntax/cartesian.scala
@@ -17,10 +17,4 @@ abstract class CartesianOps[F[_], A] extends Cartesian.Ops[F, A] {
final def |@|[B](fb: F[B]): CartesianBuilder[F]#CartesianBuilder2[A, B] =
new CartesianBuilder[F] |@| self |@| fb
- final def *>[B](fb: F[B])(implicit F: Functor[F]): F[B] =
- F.map(typeClassInstance.product(self, fb)) { case (_, b) => b }
-
- final def <*[B](fb: F[B])(implicit F: Functor[F]): F[A] =
- F.map(typeClassInstance.product(self, fb)) { case (a, _) => a }
-
}
diff --git a/core/src/main/scala/cats/syntax/flatMap.scala b/core/src/main/scala/cats/syntax/flatMap.scala
index fb0e6d226a..4342b42788 100644
--- a/core/src/main/scala/cats/syntax/flatMap.scala
+++ b/core/src/main/scala/cats/syntax/flatMap.scala
@@ -11,6 +11,18 @@ trait FlatMapSyntax extends FlatMap.ToFlatMapOps {
implicit final def catsSyntaxFlatMapIdOps[A](a: A): FlatMapIdOps[A] =
new FlatMapIdOps[A](a)
+
+ implicit final def catsSyntaxFlatMapOps[F[_]: FlatMap, A](fa: F[A]): FlatMapOps[F, A] =
+ new FlatMapOps[F, A](fa)
+}
+
+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[B] = F.followedBy(fa)(fb)
+
+ @deprecated("Use <* instead", "1.0.0-RC1")
+ def <<[B](fb: F[B])(implicit F: FlatMap[F]): F[A] = F.forEffect(fa)(fb)
}
final class FlattenOps[F[_], A](val ffa: F[F[A]]) extends AnyVal {
diff --git a/docs/src/main/tut/faq.md b/docs/src/main/tut/faq.md
index 0fdaf8f3ef..b6eddfb462 100644
--- a/docs/src/main/tut/faq.md
+++ b/docs/src/main/tut/faq.md
@@ -210,13 +210,11 @@ All other symbols can be imported with `import cats.implicits._`
| Symbol | Name | Nickname | Type Class | Signature |
| -------------------------------- | ---------------------- | ---------------- | ----------------------- | --------------------------------------------------------- |
-| `fa *> fb` | right apply | | `Cartesian[F[_]]` | `*>(fa: F[A])(fb: F[B]): F[B]` |
-| `fa <* fb` | left apply | | `Cartesian[F[_]]` | `<*(fa: F[A])(fb: F[B]): F[A]` |
+| `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]` |
| `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` | for effect | | `FlatMap[F[_]]` | `forEffect(fa: F[A])(fb: F[B]): F[A]` |
| 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` |
@@ -231,6 +229,8 @@ All other symbols can be imported with `import cats.implicits._`
| `F :≺: G` | injectK | | `InjectK[F[_], G[_]]` | `InjectK` alias |
| `⊥` | bottom | | N/A | `Nothing` |
| `⊤` | top | | N/A | `Any` |
+| `fa >> fb` (Deprecated) | followed by | | `FlatMap[F[_]]` | `followedBy(fa: F[A])(fb: F[B]): F[B]` |
+| `fa << fb` (Deprecated) | for effect | | `FlatMap[F[_]]` | `forEffect(fa: F[A])(fb: F[B]): F[A]` |
## How can I help?
diff --git a/free/src/test/scala/cats/free/FreeTests.scala b/free/src/test/scala/cats/free/FreeTests.scala
index 0eda77a71e..d8ee9c2ba7 100644
--- a/free/src/test/scala/cats/free/FreeTests.scala
+++ b/free/src/test/scala/cats/free/FreeTests.scala
@@ -189,8 +189,8 @@ class FreeTests extends CatsSuite {
forAll { (x: Int, y: Int) =>
val expr1: Free[T, Int] = Free.injectRoll[T, Test1Algebra, Int](Test1(x, Free.pure))
val expr2: Free[T, Int] = Free.injectRoll[T, Test2Algebra, Int](Test2(y, Free.pure))
- val res = distr[T, Int](expr1 >> expr2)
- res == Some(Free.pure(x + y)) should ===(true)
+ val res = distr[T, Int](expr1 *> expr2)
+ res.map(_.foldMap(eitherKInterpreter)) should === (Some(Free.pure[Id, Int](x + y).foldMap(FunctionK.id)))
}
}
}
diff --git a/laws/src/main/scala/cats/laws/ApplyLaws.scala b/laws/src/main/scala/cats/laws/ApplyLaws.scala
index 760e7c3330..34e2ee4773 100644
--- a/laws/src/main/scala/cats/laws/ApplyLaws.scala
+++ b/laws/src/main/scala/cats/laws/ApplyLaws.scala
@@ -20,6 +20,12 @@ trait ApplyLaws[F[_]] extends FunctorLaws[F] with CartesianLaws[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]] =
+ F.followedBy(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)
}
object ApplyLaws {
diff --git a/laws/src/main/scala/cats/laws/FlatMapLaws.scala b/laws/src/main/scala/cats/laws/FlatMapLaws.scala
index 0eb8bf2b8a..93d0da15af 100644
--- a/laws/src/main/scala/cats/laws/FlatMapLaws.scala
+++ b/laws/src/main/scala/cats/laws/FlatMapLaws.scala
@@ -18,11 +18,6 @@ trait FlatMapLaws[F[_]] extends ApplyLaws[F] {
def flatMapConsistentApply[A, B](fa: F[A], fab: F[A => B]): IsEq[F[B]] =
fab.ap(fa) <-> fab.flatMap(f => fa.map(f))
- def followedByConsistency[A, B](fa: F[A], fb: F[B]): IsEq[F[B]] =
- F.followedBy(fa)(fb) <-> F.flatMap(fa)(_ => fb)
-
- def forEffectConsistency[A, B](fa: F[A], fb: F[B]): IsEq[F[A]] =
- F.forEffect(fa)(fb) <-> F.flatMap(fa)(a => fb.map(_ => a))
/**
* The composition of `cats.data.Kleisli` arrows is associative. This is
diff --git a/tests/src/test/scala/cats/tests/MonadTest.scala b/tests/src/test/scala/cats/tests/MonadTest.scala
index 900f1bb298..3232174ac2 100644
--- a/tests/src/test/scala/cats/tests/MonadTest.scala
+++ b/tests/src/test/scala/cats/tests/MonadTest.scala
@@ -10,7 +10,7 @@ class MonadTest extends CatsSuite {
val smallPosInt = Gen.choose(1, 5000)
val increment: StateT[Id, Int, Unit] = StateT.modify(_ + 1)
- val incrementAndGet: StateT[Id, Int, Int] = increment >> StateT.get
+ val incrementAndGet: StateT[Id, Int, Int] = increment *> StateT.get
test("whileM_") {
forAll(smallPosInt) { (max: Int) =>
diff --git a/tests/src/test/scala/cats/tests/SyntaxTests.scala b/tests/src/test/scala/cats/tests/SyntaxTests.scala
index 55321d5184..1d8006f3d8 100644
--- a/tests/src/test/scala/cats/tests/SyntaxTests.scala
+++ b/tests/src/test/scala/cats/tests/SyntaxTests.scala
@@ -209,6 +209,9 @@ object SyntaxTests extends AllInstances with AllSyntax {
val f = mock[(A, B, C) => Z]
val ff = mock[F[(A, B, C) => Z]]
+ fa *> fb
+ fb <* fc
+
tfabc mapN f
(fa, fb, fc) mapN f
(fa, fb, fc) apWith ff