diff --git a/core/src/main/scala/cats/Applicative.scala b/core/src/main/scala/cats/Applicative.scala index 47300f7522..93d2019ae9 100644 --- a/core/src/main/scala/cats/Applicative.scala +++ b/core/src/main/scala/cats/Applicative.scala @@ -207,6 +207,28 @@ object Applicative { */ implicit def catsApplicativeForArrow[F[_, _], A](implicit F: Arrow[F]): Applicative[F[A, ?]] = new ArrowApplicative[F, A](F) + + + /** + * Creates a CoflatMap for an Applicative `F`. + * Cannot be implicit in 1.0 for Binary Compatibility Reasons + * + * Example: + * {{{ + * scala> import cats._ + * scala> import cats.implicits._ + * scala> val fa = Some(3) + * fa: Option[Int] = Some(3) + * scala> Applicative.coflatMap[Option].coflatten(fa) + * res0: Option[Option[Int]] = Some(Some(3)) + * }}} + */ + def coflatMap[F[_]](implicit F: Applicative[F]): CoflatMap[F] = + new CoflatMap[F] { + def coflatMap[A, B](fa: F[A])(f: F[A] => B): F[B] = F.pure(f(fa)) + def map[A, B](fa: F[A])(f: A => B): F[B] = F.map(fa)(f) + } + } private[cats] class ApplicativeMonoid[F[_], A](f: Applicative[F], monoid: Monoid[A]) extends ApplySemigroup(f, monoid) with Monoid[F[A]] { diff --git a/tests/src/test/scala/cats/tests/ApplicativeSuite.scala b/tests/src/test/scala/cats/tests/ApplicativeSuite.scala index 11b0f0cce0..021dd29c2c 100644 --- a/tests/src/test/scala/cats/tests/ApplicativeSuite.scala +++ b/tests/src/test/scala/cats/tests/ApplicativeSuite.scala @@ -2,6 +2,9 @@ package cats package tests import cats.Applicative +import cats.data.{Validated, Const} +import cats.laws.discipline.arbitrary._ +import cats.laws.discipline.CoflatMapTests class ApplicativeSuite extends CatsSuite { @@ -36,4 +39,14 @@ class ApplicativeSuite extends CatsSuite { } } + implicit val listwrapperApplicative = ListWrapper.applicative + implicit val listwrapperCoflatMap = Applicative.coflatMap[ListWrapper] + checkAll("Applicative[ListWrapper].coflatMap", CoflatMapTests[ListWrapper].coflatMap[String, String, String]) + + implicit val validatedCoflatMap = Applicative.coflatMap[Validated[String, ?]] + checkAll("Applicative[Validated].coflatMap", CoflatMapTests[Validated[String, ?]].coflatMap[String, String, String]) + + implicit val constCoflatMap = Applicative.coflatMap[Const[String, ?]] + checkAll("Applicative[Const].coflatMap", CoflatMapTests[Const[String, ?]].coflatMap[String, String, String]) + }