diff --git a/core/src/main/scala/cats/syntax/all.scala b/core/src/main/scala/cats/syntax/all.scala index e087eed366..c90ef1b8e7 100644 --- a/core/src/main/scala/cats/syntax/all.scala +++ b/core/src/main/scala/cats/syntax/all.scala @@ -81,6 +81,7 @@ trait AllSyntaxBinCompat3 extends UnorderedFoldableSyntax with Function1Syntax trait AllSyntaxBinCompat4 extends TraverseFilterSyntaxBinCompat0 + with ApplySyntaxBinCompat0 with ParallelApplySyntax with FoldableSyntaxBinCompat0 with ReducibleSyntaxBinCompat0 diff --git a/core/src/main/scala/cats/syntax/apply.scala b/core/src/main/scala/cats/syntax/apply.scala index cb62157098..3c91c6221d 100644 --- a/core/src/main/scala/cats/syntax/apply.scala +++ b/core/src/main/scala/cats/syntax/apply.scala @@ -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]]. */