diff --git a/core/src/main/scala/cats/Eval.scala b/core/src/main/scala/cats/Eval.scala index 36348160fea..934e6d12372 100644 --- a/core/src/main/scala/cats/Eval.scala +++ b/core/src/main/scala/cats/Eval.scala @@ -294,8 +294,8 @@ object Eval extends EvalInstances { private[cats] trait EvalInstances extends EvalInstances0 { - implicit val catsBimonadForEval: Bimonad[Eval] with Monad[Eval] with RecursiveTailRecM[Eval] = - new Bimonad[Eval] with Monad[Eval] with RecursiveTailRecM[Eval] { + implicit val catsBimonadForEval: Bimonad[Eval] with Monad[Eval] = + new Bimonad[Eval] with Monad[Eval] { override def map[A, B](fa: Eval[A])(f: A => B): Eval[B] = fa.map(f) def pure[A](a: A): Eval[A] = Now(a) def flatMap[A, B](fa: Eval[A])(f: A => Eval[B]): Eval[B] = fa.flatMap(f) diff --git a/core/src/main/scala/cats/RecursiveTailRecM.scala b/core/src/main/scala/cats/RecursiveTailRecM.scala deleted file mode 100644 index 2519806e5b5..00000000000 --- a/core/src/main/scala/cats/RecursiveTailRecM.scala +++ /dev/null @@ -1,24 +0,0 @@ -package cats - -import java.io.Serializable -/** - * This is a marker type that promises that the method - * .tailRecM for this type is stack-safe for arbitrary recursion. - */ -trait RecursiveTailRecM[F[_]] extends Serializable { - /* - * you can call RecursiveTailRecM[F].sameType(Monad[F]).tailRec - * to have a static check that the types agree - * for safer usage of tailRecM - */ - final def sameType[M[_[_]]](m: M[F]): M[F] = m -} - -object RecursiveTailRecM { - private[this] val singleton: RecursiveTailRecM[Id] = new RecursiveTailRecM[Id] { } - - def apply[F[_]](implicit r: RecursiveTailRecM[F]): RecursiveTailRecM[F] = r - - def create[F[_]]: RecursiveTailRecM[F] = - singleton.asInstanceOf[RecursiveTailRecM[F]] -} diff --git a/core/src/main/scala/cats/data/Cokleisli.scala b/core/src/main/scala/cats/data/Cokleisli.scala index 752a200c74c..cc77a7d0472 100644 --- a/core/src/main/scala/cats/data/Cokleisli.scala +++ b/core/src/main/scala/cats/data/Cokleisli.scala @@ -48,7 +48,7 @@ private[data] sealed abstract class CokleisliInstances extends CokleisliInstance implicit def catsDataArrowForCokleisli[F[_]](implicit ev: Comonad[F]): Arrow[Cokleisli[F, ?, ?]] = new CokleisliArrow[F] { def F: Comonad[F] = ev } - implicit def catsDataMonadForCokleisli[F[_], A]: Monad[Cokleisli[F, A, ?]] with RecursiveTailRecM[Cokleisli[F, A, ?]] = new Monad[Cokleisli[F, A, ?]] with RecursiveTailRecM[Cokleisli[F, A, ?]] { + implicit def catsDataMonadForCokleisli[F[_], A]: Monad[Cokleisli[F, A, ?]] = new Monad[Cokleisli[F, A, ?]] { def pure[B](x: B): Cokleisli[F, A, B] = Cokleisli.pure(x) diff --git a/core/src/main/scala/cats/data/EitherT.scala b/core/src/main/scala/cats/data/EitherT.scala index 38eab701feb..59361206421 100644 --- a/core/src/main/scala/cats/data/EitherT.scala +++ b/core/src/main/scala/cats/data/EitherT.scala @@ -345,9 +345,6 @@ private[data] abstract class EitherTInstances2 extends EitherTInstances3 { implicit def catsDataMonadErrorForEitherT[F[_], L](implicit F0: Monad[F]): MonadError[EitherT[F, L, ?], L] = new EitherTMonadError[F, L] { implicit val F = F0 } - implicit def catsDataRecursiveTailRecMForEitherT[F[_]: RecursiveTailRecM, L]: RecursiveTailRecM[EitherT[F, L, ?]] = - RecursiveTailRecM.create[EitherT[F, L, ?]] - implicit def catsDataSemigroupKForEitherT[F[_], L](implicit F0: Monad[F]): SemigroupK[EitherT[F, L, ?]] = new EitherTSemigroupK[F, L] { implicit val F = F0 } diff --git a/core/src/main/scala/cats/data/IdT.scala b/core/src/main/scala/cats/data/IdT.scala index 0c619079c0e..e853a7b64ee 100644 --- a/core/src/main/scala/cats/data/IdT.scala +++ b/core/src/main/scala/cats/data/IdT.scala @@ -86,9 +86,6 @@ private[data] sealed abstract class IdTInstances0 extends IdTInstances1 { implicit val F0: Monad[F] = F } - implicit def catsDataRecursiveTailRecMForIdT[F[_]: RecursiveTailRecM]: RecursiveTailRecM[IdT[F, ?]] = - RecursiveTailRecM.create[IdT[F, ?]] - implicit def catsDataFoldableForIdT[F[_]](implicit F: Foldable[F]): Foldable[IdT[F, ?]] = new IdTFoldable[F] { implicit val F0: Foldable[F] = F diff --git a/core/src/main/scala/cats/data/Ior.scala b/core/src/main/scala/cats/data/Ior.scala index 4adf44d61d5..a1aa8827553 100644 --- a/core/src/main/scala/cats/data/Ior.scala +++ b/core/src/main/scala/cats/data/Ior.scala @@ -144,7 +144,7 @@ private[data] sealed abstract class IorInstances extends IorInstances0 { def combine(x: Ior[A, B], y: Ior[A, B]) = x.append(y) } - implicit def catsDataMonadForIor[A: Semigroup]: Monad[A Ior ?] with RecursiveTailRecM[A Ior ?] = new Monad[A Ior ?] with RecursiveTailRecM[A Ior ?] { + implicit def catsDataMonadForIor[A: Semigroup]: Monad[A Ior ?] = new Monad[A Ior ?] { def pure[B](b: B): A Ior B = Ior.right(b) def flatMap[B, C](fa: A Ior B)(f: B => A Ior C): A Ior C = fa.flatMap(f) def tailRecM[B, C](b: B)(fn: B => Ior[A, Either[B, C]]): A Ior C = { diff --git a/core/src/main/scala/cats/data/Kleisli.scala b/core/src/main/scala/cats/data/Kleisli.scala index 0d7552997f9..27de9974022 100644 --- a/core/src/main/scala/cats/data/Kleisli.scala +++ b/core/src/main/scala/cats/data/Kleisli.scala @@ -149,9 +149,6 @@ private[data] sealed abstract class KleisliInstances0 extends KleisliInstances1 Kleisli[F, A, C]({ a => FlatMap[F].tailRecM(b) { f(_).run(a) } }) } - implicit def catsDataRecursiveTailRecMForKleisli[F[_]: RecursiveTailRecM, A]: RecursiveTailRecM[Kleisli[F, A, ?]] = - RecursiveTailRecM.create[Kleisli[F, A, ?]] - implicit def catsDataSemigroupForKleisli[F[_], A, B](implicit M: Semigroup[F[B]]): Semigroup[Kleisli[F, A, B]] = new KleisliSemigroup[F, A, B] { def FB: Semigroup[F[B]] = M } diff --git a/core/src/main/scala/cats/data/NonEmptyList.scala b/core/src/main/scala/cats/data/NonEmptyList.scala index 9aaffa7bde1..6dc3b7ca612 100644 --- a/core/src/main/scala/cats/data/NonEmptyList.scala +++ b/core/src/main/scala/cats/data/NonEmptyList.scala @@ -161,9 +161,9 @@ object NonEmptyList extends NonEmptyListInstances { private[data] sealed trait NonEmptyListInstances extends NonEmptyListInstances0 { implicit val catsDataInstancesForNonEmptyList: SemigroupK[NonEmptyList] with Reducible[NonEmptyList] - with Comonad[NonEmptyList] with Traverse[NonEmptyList] with Monad[NonEmptyList] with RecursiveTailRecM[NonEmptyList] = + with Comonad[NonEmptyList] with Traverse[NonEmptyList] with Monad[NonEmptyList] = new NonEmptyReducible[NonEmptyList, List] with SemigroupK[NonEmptyList] with Comonad[NonEmptyList] - with Traverse[NonEmptyList] with Monad[NonEmptyList] with RecursiveTailRecM[NonEmptyList] { + with Traverse[NonEmptyList] with Monad[NonEmptyList] { def combineK[A](a: NonEmptyList[A], b: NonEmptyList[A]): NonEmptyList[A] = a concat b diff --git a/core/src/main/scala/cats/data/NonEmptyVector.scala b/core/src/main/scala/cats/data/NonEmptyVector.scala index d602795ceb8..2cc61ebe277 100644 --- a/core/src/main/scala/cats/data/NonEmptyVector.scala +++ b/core/src/main/scala/cats/data/NonEmptyVector.scala @@ -169,9 +169,9 @@ final class NonEmptyVector[A] private (val toVector: Vector[A]) extends AnyVal { private[data] sealed trait NonEmptyVectorInstances { implicit val catsDataInstancesForNonEmptyVector: SemigroupK[NonEmptyVector] with Reducible[NonEmptyVector] - with Comonad[NonEmptyVector] with Traverse[NonEmptyVector] with Monad[NonEmptyVector] with RecursiveTailRecM[NonEmptyVector] = + with Comonad[NonEmptyVector] with Traverse[NonEmptyVector] with Monad[NonEmptyVector] = new NonEmptyReducible[NonEmptyVector, Vector] with SemigroupK[NonEmptyVector] with Comonad[NonEmptyVector] - with Traverse[NonEmptyVector] with Monad[NonEmptyVector] with RecursiveTailRecM[NonEmptyVector] { + with Traverse[NonEmptyVector] with Monad[NonEmptyVector] { def combineK[A](a: NonEmptyVector[A], b: NonEmptyVector[A]): NonEmptyVector[A] = a concatNev b diff --git a/core/src/main/scala/cats/data/OneAnd.scala b/core/src/main/scala/cats/data/OneAnd.scala index ee50730ebb9..9368ed91794 100644 --- a/core/src/main/scala/cats/data/OneAnd.scala +++ b/core/src/main/scala/cats/data/OneAnd.scala @@ -169,9 +169,6 @@ private[data] sealed trait OneAndInstances extends OneAndLowPriority2 { go(a, Nil) } } - - implicit def catsDataOneAnd[F[_]: RecursiveTailRecM]: RecursiveTailRecM[OneAnd[F, ?]] = - RecursiveTailRecM.create[OneAnd[F, ?]] } private[data] trait OneAndLowPriority0 { diff --git a/core/src/main/scala/cats/data/OptionT.scala b/core/src/main/scala/cats/data/OptionT.scala index 364a8e4583e..ebceaa70abb 100644 --- a/core/src/main/scala/cats/data/OptionT.scala +++ b/core/src/main/scala/cats/data/OptionT.scala @@ -196,9 +196,6 @@ private[data] sealed trait OptionTInstances0 extends OptionTInstances1 { implicit def catsDataMonadErrorForOptionT[F[_], E](implicit F0: MonadError[F, E]): MonadError[OptionT[F, ?], E] = new OptionTMonadError[F, E] { implicit val F = F0 } - implicit def catsDataRecursiveTailRecMForOptionT[F[_]](implicit F: RecursiveTailRecM[F]): RecursiveTailRecM[OptionT[F, ?]] = - RecursiveTailRecM.create[OptionT[F, ?]] - implicit def catsDataSemigroupKForOptionT[F[_]](implicit F0: Monad[F]): SemigroupK[OptionT[F, ?]] = new OptionTSemigroupK[F] { implicit val F = F0 } diff --git a/core/src/main/scala/cats/data/StateT.scala b/core/src/main/scala/cats/data/StateT.scala index 75b0c10401f..96ec613a3af 100644 --- a/core/src/main/scala/cats/data/StateT.scala +++ b/core/src/main/scala/cats/data/StateT.scala @@ -169,8 +169,6 @@ private[data] sealed trait StateTInstances2 { implicit def catsDataMonadForStateT[F[_], S](implicit F0: Monad[F]): Monad[StateT[F, S, ?]] = new StateTMonad[F, S] { implicit def F = F0 } - implicit def catsDataRecursiveTailRecMForStateT[F[_]: RecursiveTailRecM, S]: RecursiveTailRecM[StateT[F, S, ?]] = RecursiveTailRecM.create[StateT[F, S, ?]] - implicit def catsDataSemigroupKForStateT[F[_], S](implicit F0: Monad[F], G0: SemigroupK[F]): SemigroupK[StateT[F, S, ?]] = new StateTSemigroupK[F, S] { implicit def F = F0; implicit def G = G0 } } diff --git a/core/src/main/scala/cats/data/WriterT.scala b/core/src/main/scala/cats/data/WriterT.scala index 9c85d97f52b..e1f68fc8b7d 100644 --- a/core/src/main/scala/cats/data/WriterT.scala +++ b/core/src/main/scala/cats/data/WriterT.scala @@ -126,9 +126,6 @@ private[data] sealed abstract class WriterTInstances1 extends WriterTInstances2 implicit def catsDataCoflatMapForWriterTId[L]: CoflatMap[WriterT[Id, L, ?]] = catsDataCoflatMapForWriterT[Id, L] - - implicit def catsDataRecursiveTailRecMForWriterT1[F[_]: RecursiveTailRecM, L]: RecursiveTailRecM[WriterT[F, L, ?]] = - RecursiveTailRecM.create[WriterT[F, L, ?]] } private[data] sealed abstract class WriterTInstances2 extends WriterTInstances3 { diff --git a/core/src/main/scala/cats/instances/either.scala b/core/src/main/scala/cats/instances/either.scala index 64777fd1811..6f29dc82a17 100644 --- a/core/src/main/scala/cats/instances/either.scala +++ b/core/src/main/scala/cats/instances/either.scala @@ -28,8 +28,8 @@ trait EitherInstances extends cats.kernel.instances.EitherInstances { } // scalastyle:off method.length - implicit def catsStdInstancesForEither[A]: MonadError[Either[A, ?], A] with Traverse[Either[A, ?]] with RecursiveTailRecM[Either[A, ?]] = - new MonadError[Either[A, ?], A] with Traverse[Either[A, ?]] with RecursiveTailRecM[Either[A, ?]] { + implicit def catsStdInstancesForEither[A]: MonadError[Either[A, ?], A] with Traverse[Either[A, ?]] = + new MonadError[Either[A, ?], A] with Traverse[Either[A, ?]] { def pure[B](b: B): Either[A, B] = Right(b) def flatMap[B, C](fa: Either[A, B])(f: B => Either[A, C]): Either[A, C] = diff --git a/core/src/main/scala/cats/instances/function.scala b/core/src/main/scala/cats/instances/function.scala index 13fe53733e9..38711dabe32 100644 --- a/core/src/main/scala/cats/instances/function.scala +++ b/core/src/main/scala/cats/instances/function.scala @@ -11,8 +11,8 @@ trait FunctionInstances extends cats.kernel.instances.FunctionInstances private[instances] sealed trait Function0Instances { - implicit val catsStdBimonadForFunction0: Bimonad[Function0] with RecursiveTailRecM[Function0] = - new Bimonad[Function0] with RecursiveTailRecM[Function0] { + implicit val catsStdBimonadForFunction0: Bimonad[Function0] = + new Bimonad[Function0] { def extract[A](x: () => A): A = x() def coflatMap[A, B](fa: () => A)(f: (() => A) => B): () => B = @@ -42,8 +42,8 @@ private[instances] sealed trait Function1Instances { fa.compose(f) } - implicit def catsStdMonadReaderForFunction1[T1]: MonadReader[T1 => ?, T1] with RecursiveTailRecM[T1 => ?] = - new MonadReader[T1 => ?, T1] with RecursiveTailRecM[T1 => ?] { + implicit def catsStdMonadReaderForFunction1[T1]: MonadReader[T1 => ?, T1] = + new MonadReader[T1 => ?, T1] { def pure[R](r: R): T1 => R = _ => r def flatMap[R1, R2](fa: T1 => R1)(f: R1 => T1 => R2): T1 => R2 = diff --git a/core/src/main/scala/cats/instances/future.scala b/core/src/main/scala/cats/instances/future.scala index 216a56c4260..112678e96e4 100644 --- a/core/src/main/scala/cats/instances/future.scala +++ b/core/src/main/scala/cats/instances/future.scala @@ -6,8 +6,8 @@ import scala.concurrent.{ExecutionContext, Future} trait FutureInstances extends FutureInstances1 { - implicit def catsStdInstancesForFuture(implicit ec: ExecutionContext): MonadError[Future, Throwable] with CoflatMap[Future] with Monad[Future] with RecursiveTailRecM[Future] = - new FutureCoflatMap with MonadError[Future, Throwable] with Monad[Future] with RecursiveTailRecM[Future] { + implicit def catsStdInstancesForFuture(implicit ec: ExecutionContext): MonadError[Future, Throwable] with CoflatMap[Future] with Monad[Future] = + new FutureCoflatMap with MonadError[Future, Throwable] with Monad[Future] { def pure[A](x: A): Future[A] = Future.successful(x) def flatMap[A, B](fa: Future[A])(f: A => Future[B]): Future[B] = fa.flatMap(f) diff --git a/core/src/main/scala/cats/instances/list.scala b/core/src/main/scala/cats/instances/list.scala index bf982d8eed7..3ff790c1464 100644 --- a/core/src/main/scala/cats/instances/list.scala +++ b/core/src/main/scala/cats/instances/list.scala @@ -8,9 +8,8 @@ import scala.collection.mutable.ListBuffer trait ListInstances extends cats.kernel.instances.ListInstances { - implicit val catsStdInstancesForList: TraverseFilter[List] with MonadCombine[List] with Monad[List] with CoflatMap[List] with RecursiveTailRecM[List] = - new TraverseFilter[List] with MonadCombine[List] with Monad[List] with CoflatMap[List] with RecursiveTailRecM[List] { - + implicit val catsStdInstancesForList: TraverseFilter[List] with MonadCombine[List] with Monad[List] with CoflatMap[List] = + new TraverseFilter[List] with MonadCombine[List] with Monad[List] with CoflatMap[List] { def empty[A]: List[A] = Nil def combineK[A](x: List[A], y: List[A]): List[A] = x ++ y diff --git a/core/src/main/scala/cats/instances/map.scala b/core/src/main/scala/cats/instances/map.scala index 682a627b36b..7784f428e50 100644 --- a/core/src/main/scala/cats/instances/map.scala +++ b/core/src/main/scala/cats/instances/map.scala @@ -14,8 +14,8 @@ trait MapInstances extends cats.kernel.instances.MapInstances { } // scalastyle:off method.length - implicit def catsStdInstancesForMap[K]: TraverseFilter[Map[K, ?]] with FlatMap[Map[K, ?]] with RecursiveTailRecM[Map[K, ?]] = - new TraverseFilter[Map[K, ?]] with FlatMap[Map[K, ?]] with RecursiveTailRecM[Map[K, ?]] { + implicit def catsStdInstancesForMap[K]: TraverseFilter[Map[K, ?]] with FlatMap[Map[K, ?]] = + new TraverseFilter[Map[K, ?]] with FlatMap[Map[K, ?]] { override def traverse[G[_], A, B](fa: Map[K, A])(f: A => G[B])(implicit G: Applicative[G]): G[Map[K, B]] = { val gba: Eval[G[Map[K, B]]] = Always(G.pure(Map.empty)) diff --git a/core/src/main/scala/cats/instances/option.scala b/core/src/main/scala/cats/instances/option.scala index b9ca152996c..3ce0a096f21 100644 --- a/core/src/main/scala/cats/instances/option.scala +++ b/core/src/main/scala/cats/instances/option.scala @@ -5,8 +5,8 @@ import scala.annotation.tailrec trait OptionInstances extends cats.kernel.instances.OptionInstances { - implicit val catsStdInstancesForOption: TraverseFilter[Option] with MonadError[Option, Unit] with MonadCombine[Option] with Monad[Option] with CoflatMap[Option] with Alternative[Option] with RecursiveTailRecM[Option] = - new TraverseFilter[Option] with MonadError[Option, Unit] with MonadCombine[Option] with Monad[Option] with CoflatMap[Option] with Alternative[Option] with RecursiveTailRecM[Option] { + implicit val catsStdInstancesForOption: TraverseFilter[Option] with MonadError[Option, Unit] with MonadCombine[Option] with Monad[Option] with CoflatMap[Option] with Alternative[Option] = + new TraverseFilter[Option] with MonadError[Option, Unit] with MonadCombine[Option] with Monad[Option] with CoflatMap[Option] with Alternative[Option] { def empty[A]: Option[A] = None diff --git a/core/src/main/scala/cats/instances/stream.scala b/core/src/main/scala/cats/instances/stream.scala index 904358fb631..5ffcd171df6 100644 --- a/core/src/main/scala/cats/instances/stream.scala +++ b/core/src/main/scala/cats/instances/stream.scala @@ -5,8 +5,8 @@ import cats.syntax.show._ import scala.annotation.tailrec trait StreamInstances extends cats.kernel.instances.StreamInstances { - implicit val catsStdInstancesForStream: TraverseFilter[Stream] with MonadCombine[Stream] with CoflatMap[Stream] with RecursiveTailRecM[Stream] = - new TraverseFilter[Stream] with MonadCombine[Stream] with CoflatMap[Stream] with RecursiveTailRecM[Stream] { + implicit val catsStdInstancesForStream: TraverseFilter[Stream] with MonadCombine[Stream] with CoflatMap[Stream] = + new TraverseFilter[Stream] with MonadCombine[Stream] with CoflatMap[Stream] { def empty[A]: Stream[A] = Stream.Empty diff --git a/core/src/main/scala/cats/instances/try.scala b/core/src/main/scala/cats/instances/try.scala index e96d6bb5110..faacee1f571 100644 --- a/core/src/main/scala/cats/instances/try.scala +++ b/core/src/main/scala/cats/instances/try.scala @@ -10,8 +10,8 @@ import scala.annotation.tailrec trait TryInstances extends TryInstances1 { // scalastyle:off method.length - implicit def catsStdInstancesForTry: MonadError[Try, Throwable] with CoflatMap[Try] with Traverse[Try] with Monad[Try] with RecursiveTailRecM[Try] = - new TryCoflatMap with MonadError[Try, Throwable] with Traverse[Try] with Monad[Try] with RecursiveTailRecM[Try] { + implicit def catsStdInstancesForTry: MonadError[Try, Throwable] with CoflatMap[Try] with Traverse[Try] with Monad[Try] = + new TryCoflatMap with MonadError[Try, Throwable] with Traverse[Try] with Monad[Try] { def pure[A](x: A): Try[A] = Success(x) override def product[A, B](ta: Try[A], tb: Try[B]): Try[(A, B)] = (ta, tb) match { diff --git a/core/src/main/scala/cats/instances/tuple.scala b/core/src/main/scala/cats/instances/tuple.scala index 9a1acfe5832..f4aed0e05b0 100644 --- a/core/src/main/scala/cats/instances/tuple.scala +++ b/core/src/main/scala/cats/instances/tuple.scala @@ -44,18 +44,18 @@ sealed trait Tuple2Instances extends Tuple2Instances1 { } sealed trait Tuple2Instances1 extends Tuple2Instances2 { - implicit def catsStdMonadForTuple2[X](implicit MX: Monoid[X]): Monad[(X, ?)] with RecursiveTailRecM[(X, ?)] = + implicit def catsStdMonadForTuple2[X](implicit MX: Monoid[X]): Monad[(X, ?)] = new FlatMapTuple2[X](MX) with Monad[(X, ?)] { def pure[A](a: A): (X, A) = (MX.empty, a) } } sealed trait Tuple2Instances2 { - implicit def catsStdFlatMapForTuple2[X](implicit SX: Semigroup[X]): FlatMap[(X, ?)] with RecursiveTailRecM[(X, ?)]= + implicit def catsStdFlatMapForTuple2[X](implicit SX: Semigroup[X]): FlatMap[(X, ?)] = new FlatMapTuple2[X](SX) } -private[instances] class FlatMapTuple2[X](s: Semigroup[X]) extends FlatMap[(X, ?)] with RecursiveTailRecM[(X, ?)] { +private[instances] class FlatMapTuple2[X](s: Semigroup[X]) extends FlatMap[(X, ?)] { override def ap[A, B](ff: (X, A => B))(fa: (X, A)): (X, B) = { val x = s.combine(ff._1, fa._1) val b = ff._2(fa._2) diff --git a/core/src/main/scala/cats/instances/vector.scala b/core/src/main/scala/cats/instances/vector.scala index cdbf80f94d8..4b91a414c43 100644 --- a/core/src/main/scala/cats/instances/vector.scala +++ b/core/src/main/scala/cats/instances/vector.scala @@ -7,8 +7,8 @@ import scala.collection.+: import scala.collection.immutable.VectorBuilder trait VectorInstances extends cats.kernel.instances.VectorInstances { - implicit val catsStdInstancesForVector: TraverseFilter[Vector] with MonadCombine[Vector] with CoflatMap[Vector] with RecursiveTailRecM[Vector] = - new TraverseFilter[Vector] with MonadCombine[Vector] with CoflatMap[Vector] with RecursiveTailRecM[Vector] { + implicit val catsStdInstancesForVector: TraverseFilter[Vector] with MonadCombine[Vector] with CoflatMap[Vector] = + new TraverseFilter[Vector] with MonadCombine[Vector] with CoflatMap[Vector] { def empty[A]: Vector[A] = Vector.empty[A] diff --git a/core/src/main/scala/cats/package.scala b/core/src/main/scala/cats/package.scala index e0708dd7876..1643380a327 100644 --- a/core/src/main/scala/cats/package.scala +++ b/core/src/main/scala/cats/package.scala @@ -27,8 +27,8 @@ package object cats { * encodes pure unary function application. */ type Id[A] = A - implicit val catsInstancesForId: Bimonad[Id] with Monad[Id] with Traverse[Id] with RecursiveTailRecM[Id] = - new Bimonad[Id] with Monad[Id] with Traverse[Id] with RecursiveTailRecM[Id] { + implicit val catsInstancesForId: Bimonad[Id] with Monad[Id] with Traverse[Id] = + new Bimonad[Id] with Monad[Id] with Traverse[Id] { def pure[A](a: A): A = a def extract[A](a: A): A = a def flatMap[A, B](a: A)(f: A => B): B = f(a) diff --git a/laws/src/main/scala/cats/laws/MonadLaws.scala b/laws/src/main/scala/cats/laws/MonadLaws.scala index 79620c6318b..cfcd028f5c4 100644 --- a/laws/src/main/scala/cats/laws/MonadLaws.scala +++ b/laws/src/main/scala/cats/laws/MonadLaws.scala @@ -35,6 +35,12 @@ trait MonadLaws[F[_]] extends ApplicativeLaws[F] with FlatMapLaws[F] { */ def mapFlatMapCoherence[A, B](fa: F[A], f: A => B): IsEq[F[B]] = fa.flatMap(a => F.pure(f(a))) <-> fa.map(f) + + val tailRecMStackSafety: IsEq[F[Int]] = { + val n = 50000 + val res = F.tailRecM(0)(i => F.pure(if (i < n) Either.left(i + 1) else Either.right(i))) + res <-> F.pure(n) + } } object MonadLaws { diff --git a/laws/src/main/scala/cats/laws/discipline/BimonadTests.scala b/laws/src/main/scala/cats/laws/discipline/BimonadTests.scala index fb9f545dda2..9d1a7508d69 100644 --- a/laws/src/main/scala/cats/laws/discipline/BimonadTests.scala +++ b/laws/src/main/scala/cats/laws/discipline/BimonadTests.scala @@ -23,6 +23,7 @@ trait BimonadTests[F[_]] extends MonadTests[F] with ComonadTests[F] { EqFB: Eq[F[B]], EqFC: Eq[F[C]], EqFABC: Eq[F[(A, B, C)]], + EqFInt: Eq[F[Int]], iso: Isomorphisms[F] ): RuleSet = { new RuleSet { diff --git a/laws/src/main/scala/cats/laws/discipline/MonadCombineTests.scala b/laws/src/main/scala/cats/laws/discipline/MonadCombineTests.scala index be6ec6ed11b..ff0b0b90e30 100644 --- a/laws/src/main/scala/cats/laws/discipline/MonadCombineTests.scala +++ b/laws/src/main/scala/cats/laws/discipline/MonadCombineTests.scala @@ -20,6 +20,7 @@ trait MonadCombineTests[F[_]] extends MonadFilterTests[F] with AlternativeTests[ EqFB: Eq[F[B]], EqFC: Eq[F[C]], EqFABC: Eq[F[(A, B, C)]], + EqFInt: Eq[F[Int]], iso: Isomorphisms[F] ): RuleSet = { new RuleSet { diff --git a/laws/src/main/scala/cats/laws/discipline/MonadErrorTests.scala b/laws/src/main/scala/cats/laws/discipline/MonadErrorTests.scala index 74bca14988f..fc6745e2d4b 100644 --- a/laws/src/main/scala/cats/laws/discipline/MonadErrorTests.scala +++ b/laws/src/main/scala/cats/laws/discipline/MonadErrorTests.scala @@ -25,6 +25,7 @@ trait MonadErrorTests[F[_], E] extends ApplicativeErrorTests[F, E] with MonadTes EqFEitherEA: Eq[F[Either[E, A]]], EqEitherTFEA: Eq[EitherT[F, E, A]], EqFABC: Eq[F[(A, B, C)]], + EqFInt: Eq[F[Int]], iso: Isomorphisms[F] ): RuleSet = { new RuleSet { diff --git a/laws/src/main/scala/cats/laws/discipline/MonadFilterTests.scala b/laws/src/main/scala/cats/laws/discipline/MonadFilterTests.scala index bfdb555fd64..a278139434e 100644 --- a/laws/src/main/scala/cats/laws/discipline/MonadFilterTests.scala +++ b/laws/src/main/scala/cats/laws/discipline/MonadFilterTests.scala @@ -20,6 +20,7 @@ trait MonadFilterTests[F[_]] extends MonadTests[F] with FunctorFilterTests[F] { EqFB: Eq[F[B]], EqFC: Eq[F[C]], EqFABC: Eq[F[(A, B, C)]], + EqFInt: Eq[F[Int]], iso: Isomorphisms[F] ): RuleSet = { new RuleSet { diff --git a/laws/src/main/scala/cats/laws/discipline/MonadReaderTests.scala b/laws/src/main/scala/cats/laws/discipline/MonadReaderTests.scala index 10f25078167..f5a07f71738 100644 --- a/laws/src/main/scala/cats/laws/discipline/MonadReaderTests.scala +++ b/laws/src/main/scala/cats/laws/discipline/MonadReaderTests.scala @@ -21,6 +21,7 @@ trait MonadReaderTests[F[_], R] extends MonadTests[F] { EqFC: Eq[F[C]], EqFR: Eq[F[R]], EqFABC: Eq[F[(A, B, C)]], + EqFInt: Eq[F[Int]], iso: Isomorphisms[F] ): RuleSet = { new RuleSet { diff --git a/laws/src/main/scala/cats/laws/discipline/MonadStateTests.scala b/laws/src/main/scala/cats/laws/discipline/MonadStateTests.scala index c27d93d7ac0..e70ffe0e47a 100644 --- a/laws/src/main/scala/cats/laws/discipline/MonadStateTests.scala +++ b/laws/src/main/scala/cats/laws/discipline/MonadStateTests.scala @@ -24,6 +24,7 @@ trait MonadStateTests[F[_], S] extends MonadTests[F] { EqFUnit: Eq[F[Unit]], EqFS: Eq[F[S]], EqFABC: Eq[F[(A, B, C)]], + EqFInt: Eq[F[Int]], iso: Isomorphisms[F] ): RuleSet = { new RuleSet { diff --git a/laws/src/main/scala/cats/laws/discipline/MonadTests.scala b/laws/src/main/scala/cats/laws/discipline/MonadTests.scala index 50e6a560398..42741bae5d7 100644 --- a/laws/src/main/scala/cats/laws/discipline/MonadTests.scala +++ b/laws/src/main/scala/cats/laws/discipline/MonadTests.scala @@ -20,6 +20,7 @@ trait MonadTests[F[_]] extends ApplicativeTests[F] with FlatMapTests[F] { EqFB: Eq[F[B]], EqFC: Eq[F[C]], EqFABC: Eq[F[(A, B, C)]], + EqFInt: Eq[F[Int]], iso: Isomorphisms[F] ): RuleSet = { new RuleSet { @@ -29,7 +30,8 @@ trait MonadTests[F[_]] extends ApplicativeTests[F] with FlatMapTests[F] { def props: Seq[(String, Prop)] = Seq( "monad left identity" -> forAll(laws.monadLeftIdentity[A, B] _), "monad right identity" -> forAll(laws.monadRightIdentity[A] _), - "map flatMap coherence" -> forAll(laws.mapFlatMapCoherence[A, B] _) + "map flatMap coherence" -> forAll(laws.mapFlatMapCoherence[A, B] _), + "tailRecM stack safety" -> laws.tailRecMStackSafety ) } } diff --git a/laws/src/main/scala/cats/laws/discipline/MonadWriterTests.scala b/laws/src/main/scala/cats/laws/discipline/MonadWriterTests.scala index e3f92eb5637..25f053c52d4 100644 --- a/laws/src/main/scala/cats/laws/discipline/MonadWriterTests.scala +++ b/laws/src/main/scala/cats/laws/discipline/MonadWriterTests.scala @@ -21,6 +21,7 @@ trait MonadWriterTests[F[_], W] extends MonadTests[F] { EqFC: Eq[F[C]], EqFU: Eq[F[Unit]], EqFABC: Eq[F[(A, B, C)]], + EqFInt: Eq[F[Int]], WA: Arbitrary[W], WM: Monoid[W], iso: Isomorphisms[F] diff --git a/tests/src/test/scala/cats/tests/MonadRecInstancesTests.scala b/tests/src/test/scala/cats/tests/MonadRecInstancesTests.scala deleted file mode 100644 index 604318ae147..00000000000 --- a/tests/src/test/scala/cats/tests/MonadRecInstancesTests.scala +++ /dev/null @@ -1,105 +0,0 @@ -package cats -package tests - -import cats.data.{ - Cokleisli, - EitherT, - IdT, - Ior, - Kleisli, - NonEmptyList, - NonEmptyVector, - OneAnd, - OptionT, - StateT, - WriterT -} - -class MonadRecInstancesTests extends CatsSuite { - def tailRecMStackSafety[M[_]: RecursiveTailRecM](implicit M: Monad[M], Eq: Eq[M[Int]]): Unit = { - val n = 50000 - val res = M.tailRecM(0)(i => M.pure(if (i < n) Either.left(i + 1) else Either.right(i))) - res should === (M.pure(n)) - } - - test("tailRecM stack-safety for Cokleisli[Option, Int, ?]") { - implicit val eq: Eq[Cokleisli[Option, Int, Int]] = new Eq[Cokleisli[Option, Int, Int]] { - def eqv(a: Cokleisli[Option, Int, Int], b: Cokleisli[Option, Int, Int]) = - a.run(None) == b.run(None) - } - tailRecMStackSafety[Cokleisli[Option, Int, ?]] - } - - test("tailRecM stack-safety for Kleisli[Option, Int, ?]") { - implicit val eq: Eq[Kleisli[Option, Int, Int]] = new Eq[Kleisli[Option, Int, Int]] { - def eqv(a: Kleisli[Option, Int, Int], b: Kleisli[Option, Int, Int]) = - a.run(0) == b.run(0) - } - tailRecMStackSafety[Kleisli[Option, Int, ?]] - } - - test("tailRecM stack-safety for Id") { - tailRecMStackSafety[Id] - } - - test("tailRecM stack-safety for IdT[Option, ?]") { - tailRecMStackSafety[IdT[Option, ?]] - } - - test("tailRecM stack-safety for Option") { - tailRecMStackSafety[Option] - } - - test("tailRecM stack-safety for OptionT") { - tailRecMStackSafety[OptionT[Option, ?]] - } - - test("tailRecM stack-safety for OneAnd[Stream, ?]") { - tailRecMStackSafety[OneAnd[Stream, ?]] - } - - test("tailRecM stack-safety for Either") { - tailRecMStackSafety[Either[String, ?]] - } - - test("tailRecM stack-safety for NonEmptyList") { - tailRecMStackSafety[NonEmptyList] - } - - test("tailRecM stack-safety for NonEmptyVector") { - tailRecMStackSafety[NonEmptyVector] - } - - test("tailRecM stack-safety for EitherT") { - tailRecMStackSafety[EitherT[Option, String, ?]] - } - - test("tailRecM stack-safety for Ior") { - tailRecMStackSafety[Int Ior ?] - } - - test("tailRecM stack-safety for List") { - tailRecMStackSafety[List] - } - - test("tailRecM stack-safety for Stream") { - tailRecMStackSafety[Stream] - } - - test("tailRecM stack-safety for Vector") { - tailRecMStackSafety[Vector] - } - - test("tailRecM stack-safety for Eval") { - tailRecMStackSafety[Eval] - } - - test("tailRecM stack-safety for StateT") { - import StateTTests._ // import implicit Eq[StateT[...]] - tailRecMStackSafety[StateT[Option, Int, ?]] - } - - test("tailRecM stack-safety for WriterT[Option, Int, ?]") { - tailRecMStackSafety[WriterT[Option, Int, ?]] - } -}