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

Deprecate FlatMap's >> and << #1955

Merged
merged 4 commits into from
Oct 10, 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
16 changes: 16 additions & 0 deletions core/src/main/scala/cats/Apply.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Copy link
Member Author

Choose a reason for hiding this comment

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

This is untested because <* and << were before this PR.


/**
* ap2 is a binary version of ap, defined in terms of ap.
*/
Expand Down
8 changes: 0 additions & 8 deletions core/src/main/scala/cats/FlatMap.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
6 changes: 0 additions & 6 deletions core/src/main/scala/cats/syntax/cartesian.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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] =
Copy link
Contributor

Choose a reason for hiding this comment

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

Ahh. I see someone put them here originally. This was an error in my view. They should be on Apply.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah +1 on that :)

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 }

}
12 changes: 12 additions & 0 deletions core/src/main/scala/cats/syntax/flatMap.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Copy link
Member Author

Choose a reason for hiding this comment

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

These are untested, because of deprecation

}

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 {
Expand Down
8 changes: 4 additions & 4 deletions docs/src/main/tut/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -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]` |
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we not add them back to another place place in the doc?

Copy link
Member Author

Choose a reason for hiding this comment

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

I added them at the bottom with a deprecated notice

| <code>x &#124;-&#124; y</code> | 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` |
Expand All @@ -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]` |

## <a id="contributing" href="#contributing"></a>How can I help?

Expand Down
4 changes: 2 additions & 2 deletions free/src/test/scala/cats/free/FreeTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)))
}
}
}
Expand Down
6 changes: 6 additions & 0 deletions laws/src/main/scala/cats/laws/ApplyLaws.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
5 changes: 0 additions & 5 deletions laws/src/main/scala/cats/laws/FlatMapLaws.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion tests/src/test/scala/cats/tests/MonadTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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) =>
Expand Down
3 changes: 3 additions & 0 deletions tests/src/test/scala/cats/tests/SyntaxTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down