diff --git a/core/src/main/scala/cats/syntax/applicative.scala b/core/src/main/scala/cats/syntax/applicative.scala index f5c2c9a44a..e3b917b6aa 100644 --- a/core/src/main/scala/cats/syntax/applicative.scala +++ b/core/src/main/scala/cats/syntax/applicative.scala @@ -25,7 +25,12 @@ package syntax trait ApplicativeSyntax { implicit final def catsSyntaxApplicativeId[A](a: A): ApplicativeIdOps[A] = new ApplicativeIdOps[A](a) - implicit final def catsSyntaxApplicative[F[_], A](fa: F[A]): ApplicativeOps[F, A] = + implicit final def catsSyntaxApplicativeByName[F[_], A](fa: => F[A]): ApplicativeByNameOps[F, A] = + new ApplicativeByNameOps[F, A](() => fa) + implicit final def catsSyntaxApplicativeByValue[F[_], A](fa: F[A]): ApplicativeByValueOps[F, A] = + new ApplicativeByValueOps[F, A](fa) + @deprecated("Use by-value or by-name version", "2.8.0") + final def catsSyntaxApplicative[F[_], A](fa: F[A]): ApplicativeOps[F, A] = new ApplicativeOps[F, A](fa) } @@ -33,8 +38,18 @@ final class ApplicativeIdOps[A](private val a: A) extends AnyVal { def pure[F[_]](implicit F: Applicative[F]): F[A] = F.pure(a) } +@deprecated("Use by-value or by-name version", "2.8.0") final class ApplicativeOps[F[_], A](private val fa: F[A]) extends AnyVal { def replicateA(n: Int)(implicit F: Applicative[F]): F[List[A]] = F.replicateA(n, fa) def unlessA(cond: Boolean)(implicit F: Applicative[F]): F[Unit] = F.unlessA(cond)(fa) def whenA(cond: Boolean)(implicit F: Applicative[F]): F[Unit] = F.whenA(cond)(fa) } + +final class ApplicativeByValueOps[F[_], A](private val fa: F[A]) extends AnyVal { + def replicateA(n: Int)(implicit F: Applicative[F]): F[List[A]] = F.replicateA(n, fa) +} + +final class ApplicativeByNameOps[F[_], A](private val fa: () => F[A]) extends AnyVal { + def unlessA(cond: Boolean)(implicit F: Applicative[F]): F[Unit] = F.unlessA(cond)(fa()) + def whenA(cond: Boolean)(implicit F: Applicative[F]): F[Unit] = F.whenA(cond)(fa()) +} diff --git a/tests/shared/src/test/scala/cats/tests/ApplicativeSuite.scala b/tests/shared/src/test/scala/cats/tests/ApplicativeSuite.scala index b71625bd5b..2ce0dac7f7 100644 --- a/tests/shared/src/test/scala/cats/tests/ApplicativeSuite.scala +++ b/tests/shared/src/test/scala/cats/tests/ApplicativeSuite.scala @@ -63,6 +63,16 @@ class ApplicativeSuite extends CatsSuite { } } + test("by-name ops are lazy") { + var i = 0 + Option(i += 1).whenA(false) + assertEquals(i, 0) + + var j = 0 + Option(j += 1).unlessA(true) + assertEquals(j, 0) + } + { implicit val optionMonoid: Monoid[Option[Int]] = Applicative.monoid[Option, Int] checkAll("Applicative[Option].monoid", MonoidTests[Option[Int]](optionMonoid).monoid)