Skip to content

Commit

Permalink
Add an If-Then-Else operation to the Apply. (#2609)
Browse files Browse the repository at this point in the history
* Add an If-Then-Else operation to the Apply.

The `FlatMap` type-class includes a function `ifM`, which allows
evaluating a Boolean computation and, depending on the result,
choosing between one effectful computation or other.

We add to the `Apply` type-class a very similar function.

Although the function is similar to `ifM`, there is an important
difference between them, as to how they handle the effect:
- The `ifM` will run the effects of the condition `F[Boolean]`,
  followed by the effects of _only one_ of the branches.
- The `ifA` will always run the effect of the condition, that of the first
  branch, and that of the second branch, in that order.

Thus, the if-then-else part in `ifA` only applies to the inner values,
not to the effects.

* Avoid adding methods to the type class.

To preserve binary compatibility, we can not add methods to
an existing type-class, and can only use the syntax extension.

* Add traits for Binary Compatibility.

* Attend code review comments.
  • Loading branch information
diesalbla authored and kailuowang committed Jan 12, 2019
1 parent b4d1ad1 commit 974cec1
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 0 deletions.
1 change: 1 addition & 0 deletions core/src/main/scala/cats/syntax/all.scala
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ trait AllSyntaxBinCompat3 extends UnorderedFoldableSyntax with Function1Syntax

trait AllSyntaxBinCompat4
extends TraverseFilterSyntaxBinCompat0
with ApplySyntaxBinCompat0
with ParallelApplySyntax
with FoldableSyntaxBinCompat0
with ReducibleSyntaxBinCompat0
Expand Down
41 changes: 41 additions & 0 deletions core/src/main/scala/cats/syntax/apply.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,47 @@ trait ApplySyntax extends TupleSemigroupalSyntax {
new ApplyOps(fa)
}

trait ApplySyntaxBinCompat0 {
implicit final def catsSyntaxIfApplyOps[F[_]](fa: F[Boolean]): IfApplyOps[F] =
new IfApplyOps[F](fa)
}

final class IfApplyOps[F[_]](private val fcond: F[Boolean]) extends AnyVal {

/**
* An `if-then-else` lifted into the `F` context.
* This function combines the effects of the `fcond` condition and of the two branches,
* in the order in which they are given.
*
* The value of the result is, depending on the value of the condition,
* the value of the first argument, or the value of the second argument.
*
* Example:
* {{{
* scala> import cats.implicits._
*
* scala> val b1: Option[Boolean] = Some(true)
* scala> val asInt1: Option[Int] = b1.ifA(Some(1), Some(0))
* scala> asInt1.get
* res0: Int = 1
*
* scala> val b2: Option[Boolean] = Some(false)
* scala> val asInt2: Option[Int] = b2.ifA(Some(1), Some(0))
* scala> asInt2.get
* res1: Int = 0
*
* scala> val b3: Option[Boolean] = Some(true)
* scala> val asInt3: Option[Int] = b3.ifA(Some(1), None)
* asInt2: Option[Int] = None
*
* }}}
*/
def ifA[A](ifTrue: F[A], ifFalse: F[A])(implicit F: Apply[F]): F[A] = {
def ite(b: Boolean)(ifTrue: A, ifFalse: A) = if (b) ifTrue else ifFalse
F.ap2(F.map(fcond)(ite))(ifTrue, ifFalse)
}
}

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

/** Alias for [[Apply.productR]]. */
Expand Down

0 comments on commit 974cec1

Please sign in to comment.