From 39593fa03ed1d1fc9f2a3891b21e992bd2f8477d Mon Sep 17 00:00:00 2001 From: Travis Brown Date: Sat, 15 Aug 2020 04:35:39 -0500 Subject: [PATCH 1/2] Add Future instances in core to implicit scope --- core/src/main/scala/cats/Invariant.scala | 7 ++++++- core/src/main/scala/cats/Semigroupal.scala | 3 +++ js/src/test/scala/cats/tests/FutureTests.scala | 3 +-- jvm/src/test/scala/cats/tests/FutureSuite.scala | 1 - 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/core/src/main/scala/cats/Invariant.scala b/core/src/main/scala/cats/Invariant.scala index e0de33a706..678d1eab1a 100644 --- a/core/src/main/scala/cats/Invariant.scala +++ b/core/src/main/scala/cats/Invariant.scala @@ -4,10 +4,11 @@ import cats.arrow.Arrow import cats.kernel._ import simulacrum.typeclass import cats.kernel.compat.scalaVersionSpecific._ +import scala.annotation.implicitNotFound import scala.collection.immutable.{Queue, SortedMap} +import scala.concurrent.{ExecutionContext, Future} import scala.util.Try import scala.util.control.TailCalls.TailRec -import scala.annotation.implicitNotFound /** * Must obey the laws defined in cats.laws.InvariantLaws. @@ -129,6 +130,10 @@ object Invariant extends ScalaVersionSpecificInvariantInstances with InvariantIn implicit def catsInstancesForTry: MonadError[Try, Throwable] with CoflatMap[Try] = cats.instances.try_.catsStdInstancesForTry + implicit def catsInstancesForFuture(implicit + ec: ExecutionContext + ): MonadError[Future, Throwable] with CoflatMap[Future] = + cats.instances.future.catsStdInstancesForFuture(ec) implicit def catsContravariantMonoidalForOrder: ContravariantMonoidal[Order] = cats.instances.order.catsContravariantMonoidalForOrder diff --git a/core/src/main/scala/cats/Semigroupal.scala b/core/src/main/scala/cats/Semigroupal.scala index 1da60fdbef..fbb18ac3ea 100644 --- a/core/src/main/scala/cats/Semigroupal.scala +++ b/core/src/main/scala/cats/Semigroupal.scala @@ -2,6 +2,7 @@ package cats import cats.kernel.CommutativeSemigroup import scala.collection.immutable.{Queue, SortedMap, SortedSet} +import scala.concurrent.{ExecutionContext, Future} import scala.util.Try import simulacrum.typeclass import scala.annotation.implicitNotFound @@ -50,6 +51,8 @@ import scala.annotation.implicitNotFound object Semigroupal extends ScalaVersionSpecificSemigroupalInstances with SemigroupalArityFunctions { implicit def catsSemigroupalForOption: Semigroupal[Option] = cats.instances.option.catsStdInstancesForOption implicit def catsSemigroupalForTry: Semigroupal[Try] = cats.instances.try_.catsStdInstancesForTry + implicit def catsSemigroupalForFuture(implicit ec: ExecutionContext): Semigroupal[Future] = + cats.instances.future.catsStdInstancesForFuture(ec) implicit def catsSemigroupalForList: Semigroupal[List] = cats.instances.list.catsStdInstancesForList implicit def catsSemigroupalForVector: Semigroupal[Vector] = cats.instances.vector.catsStdInstancesForVector implicit def catsSemigroupalForQueue: Semigroupal[Queue] = cats.instances.queue.catsStdInstancesForQueue diff --git a/js/src/test/scala/cats/tests/FutureTests.scala b/js/src/test/scala/cats/tests/FutureTests.scala index 901a165d98..167e690848 100644 --- a/js/src/test/scala/cats/tests/FutureTests.scala +++ b/js/src/test/scala/cats/tests/FutureTests.scala @@ -1,7 +1,6 @@ package cats.js.tests import cats.Comonad -import cats.instances.FutureInstances import cats.js.instances.Await import cats.js.instances.future.futureComonad import cats.kernel.Eq @@ -15,7 +14,7 @@ import org.scalacheck.Arbitrary.arbitrary import scala.concurrent.{ExecutionContextExecutor, Future} import scala.concurrent.duration._ -class FutureTests extends CatsSuite with FutureInstances { +class FutureTests extends CatsSuite { // Replaces Scala.js's `JSExecutionContext.runNow`, which is removed in 1.0. // TODO: We shouldn't do this! See: https://github.com/scala-js/scala-js/issues/2102 implicit private object RunNowExecutionContext extends ExecutionContextExecutor { diff --git a/jvm/src/test/scala/cats/tests/FutureSuite.scala b/jvm/src/test/scala/cats/tests/FutureSuite.scala index f0f2a11e06..3d4acf7f0f 100644 --- a/jvm/src/test/scala/cats/tests/FutureSuite.scala +++ b/jvm/src/test/scala/cats/tests/FutureSuite.scala @@ -1,6 +1,5 @@ package cats.jvm.tests -import cats.instances.future._ import cats.kernel.{Eq, Semigroup} import cats.kernel.laws.discipline.{MonoidTests => MonoidLawTests, SemigroupTests => SemigroupLawTests} import cats.laws.discipline._ From 64f00f8fb0354562c4c924e3df32c3b0ebb86afa Mon Sep 17 00:00:00 2001 From: Travis Brown Date: Mon, 17 Aug 2020 01:33:19 -0500 Subject: [PATCH 2/2] Add Future instances for kernel type classes --- kernel/src/main/scala/cats/kernel/Semigroup.scala | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/kernel/src/main/scala/cats/kernel/Semigroup.scala b/kernel/src/main/scala/cats/kernel/Semigroup.scala index 7eb5584df4..b10fbcbc2a 100644 --- a/kernel/src/main/scala/cats/kernel/Semigroup.scala +++ b/kernel/src/main/scala/cats/kernel/Semigroup.scala @@ -2,6 +2,7 @@ package cats.kernel import scala.annotation.tailrec import scala.collection.immutable.{BitSet, Queue, SortedMap, SortedSet} +import scala.concurrent.{ExecutionContext, Future} import scala.concurrent.duration.{Duration, FiniteDuration} import scala.{specialized => sp} import scala.util.{Failure, Success, Try} @@ -250,6 +251,8 @@ private[kernel] trait MonoidInstances extends BandInstances { cats.kernel.instances.either.catsDataMonoidForEither[A, B] implicit def catsKernelMonoidForTry[A: Monoid]: Monoid[Try[A]] = new TryMonoid[A](Monoid[A]) + implicit def catsKernelMonoidForFuture[A](implicit A: Monoid[A], ec: ExecutionContext): Monoid[Future[A]] = + new FutureMonoid[A](A, ec) implicit def catsKernelMonoidForOption[A: Semigroup]: Monoid[Option[A]] = cats.kernel.instances.option.catsKernelStdMonoidForOption[A] } @@ -277,6 +280,8 @@ private[kernel] trait SemigroupInstances { cats.kernel.instances.either.catsDataSemigroupForEither[A, B] implicit def catsKernelSemigroupForTry[A: Semigroup]: Semigroup[Try[A]] = new TrySemigroup[A](Semigroup[A]) + implicit def catsKernelSemigroupForFuture[A](implicit A: Semigroup[A], ec: ExecutionContext): Semigroup[Future[A]] = + new FutureSemigroup[A](A, ec) } private class TryMonoid[A](A: Monoid[A]) extends TrySemigroup[A](A) with Monoid[Try[A]] { @@ -291,3 +296,13 @@ private class TrySemigroup[A](A: Semigroup[A]) extends Semigroup[Try[A]] { case (_, f) => f } } + +private class FutureMonoid[A](A: Monoid[A], ec: ExecutionContext) + extends FutureSemigroup[A](A, ec) + with Monoid[Future[A]] { + def empty: Future[A] = Future.successful(A.empty) +} + +private class FutureSemigroup[A](A: Semigroup[A], ec: ExecutionContext) extends Semigroup[Future[A]] { + def combine(x: Future[A], y: Future[A]): Future[A] = x.flatMap(xv => y.map(A.combine(xv, _))(ec))(ec) +}