Skip to content

Commit

Permalink
Remove RecursiveTailRecM, move stack safety checks into MonadLaws - f…
Browse files Browse the repository at this point in the history
…ixes #1278 and fixes #1283
  • Loading branch information
adelbertc committed Sep 12, 2016
1 parent 4bb7dbb commit 02c7e3e
Show file tree
Hide file tree
Showing 38 changed files with 85 additions and 226 deletions.
4 changes: 2 additions & 2 deletions core/src/main/scala/cats/Eval.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
24 changes: 0 additions & 24 deletions core/src/main/scala/cats/RecursiveTailRecM.scala

This file was deleted.

2 changes: 1 addition & 1 deletion core/src/main/scala/cats/data/Cokleisli.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
3 changes: 0 additions & 3 deletions core/src/main/scala/cats/data/EitherT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 }

Expand Down
3 changes: 0 additions & 3 deletions core/src/main/scala/cats/data/IdT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/scala/cats/data/Ior.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
3 changes: 0 additions & 3 deletions core/src/main/scala/cats/data/Kleisli.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 }

Expand Down
4 changes: 2 additions & 2 deletions core/src/main/scala/cats/data/NonEmptyList.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/scala/cats/data/NonEmptyVector.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 0 additions & 3 deletions core/src/main/scala/cats/data/OneAnd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
3 changes: 0 additions & 3 deletions core/src/main/scala/cats/data/OptionT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 }

Expand Down
2 changes: 0 additions & 2 deletions core/src/main/scala/cats/data/StateT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
}
Expand Down
3 changes: 0 additions & 3 deletions core/src/main/scala/cats/data/WriterT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/scala/cats/instances/either.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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] =
Expand Down
8 changes: 4 additions & 4 deletions core/src/main/scala/cats/instances/function.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down Expand Up @@ -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 =
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/scala/cats/instances/future.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
5 changes: 2 additions & 3 deletions core/src/main/scala/cats/instances/list.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/scala/cats/instances/map.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/scala/cats/instances/option.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
4 changes: 2 additions & 2 deletions core/src/main/scala/cats/instances/stream.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
4 changes: 2 additions & 2 deletions core/src/main/scala/cats/instances/try.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
6 changes: 3 additions & 3 deletions core/src/main/scala/cats/instances/tuple.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/scala/cats/instances/vector.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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]

Expand Down
4 changes: 2 additions & 2 deletions core/src/main/scala/cats/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
26 changes: 10 additions & 16 deletions free/src/main/scala/cats/free/Free.scala
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,12 @@ sealed abstract class Free[S[_], A] extends Product with Serializable {
* Run to completion, using a function that maps the resumption
* from `S` to a monad `M`.
*/
final def runM[M[_]](f: S[Free[S, A]] => M[Free[S, A]])(implicit S: Functor[S], M: Monad[M], R: RecursiveTailRecM[M]): M[A] = {
final def runM[M[_]](f: S[Free[S, A]] => M[Free[S, A]])(implicit S: Functor[S], M: Monad[M]): M[A] = {
def step(t: S[Free[S, A]]): M[Either[S[Free[S, A]], A]] =
M.map(f(t))(_.resume)

resume match {
case Left(s) => R.sameType(M).tailRecM(s)(step)
case Left(s) => M.tailRecM(s)(step)
case Right(r) => M.pure(r)
}
}
Expand All @@ -92,7 +92,7 @@ sealed abstract class Free[S[_], A] extends Product with Serializable {
* Run to completion, using monadic recursion to evaluate the
* resumption in the context of `S`.
*/
final def runTailRec(implicit S: Monad[S], r: RecursiveTailRecM[S]): S[A] = {
final def runTailRec(implicit S: Monad[S]): S[A] = {
def step(rma: Free[S, A]): S[Either[Free[S, A], A]] =
rma match {
case Pure(a) =>
Expand All @@ -109,14 +109,8 @@ sealed abstract class Free[S[_], A] extends Product with Serializable {
S.pure(Left(prev.flatMap(w => g(w).flatMap(f))))
}
}
r.sameType(S).tailRecM(this)(step)
S.tailRecM(this)(step)
}
/**
* Run to completion, using monadic recursion to evaluate the
* resumption in the context of `S` without a guarantee of stack-safety
*/
final def runTailRecUnsafe(implicit S: Monad[S]): S[A] =
runTailRec(S, RecursiveTailRecM.create)

/**
* Catamorphism for `Free`.
Expand All @@ -126,8 +120,8 @@ sealed abstract class Free[S[_], A] extends Product with Serializable {
*
* This method uses `tailRecM` to provide stack-safety.
*/
final def foldMap[M[_]](f: FunctionK[S, M])(implicit M: Monad[M], r: RecursiveTailRecM[M]): M[A] =
r.sameType(M).tailRecM(this)(_.step match {
final def foldMap[M[_]](f: FunctionK[S, M])(implicit M: Monad[M]): M[A] =
M.tailRecM(this)(_.step match {
case Pure(a) => M.pure(Right(a))
case Suspend(sa) => M.map(f(sa))(Right(_))
case FlatMapped(c, g) => M.map(c.foldMap(f))(cc => Left(g(cc)))
Expand All @@ -138,7 +132,7 @@ sealed abstract class Free[S[_], A] extends Product with Serializable {
* enough, this will work
*/
final def foldMapUnsafe[M[_]](f: FunctionK[S, M])(implicit M: Monad[M]): M[A] =
foldMap[M](f)(M, RecursiveTailRecM.create)
foldMap[M](f)


/**
Expand Down Expand Up @@ -210,8 +204,8 @@ object Free {
/**
* `Free[S, ?]` has a monad for any type constructor `S[_]`.
*/
implicit def catsFreeMonadForFree[S[_]]: Monad[Free[S, ?]] with RecursiveTailRecM[Free[S, ?]] =
new Monad[Free[S, ?]] with RecursiveTailRecM[Free[S, ?]] {
implicit def catsFreeMonadForFree[S[_]]: Monad[Free[S, ?]] =
new Monad[Free[S, ?]] {
def pure[A](a: A): Free[S, A] = Free.pure(a)
override def map[A, B](fa: Free[S, A])(f: A => B): Free[S, B] = fa.map(f)
def flatMap[A, B](a: Free[S, A])(f: A => Free[S, B]): Free[S, B] = a.flatMap(f)
Expand All @@ -231,7 +225,7 @@ object Free {
* terminate if the `foldRight` implementation for `F` and the
* `tailRecM` implementation for `G` are sufficiently lazy.
*/
def foldLeftM[F[_]: Foldable, G[_]: Monad: RecursiveTailRecM, A, B](fa: F[A], z: B)(f: (B, A) => G[B]): G[B] =
def foldLeftM[F[_]: Foldable, G[_]: Monad, A, B](fa: F[A], z: B)(f: (B, A) => G[B]): G[B] =
unsafeFoldLeftM[F, Free[G, ?], A, B](fa, z) { (b, a) =>
Free.liftF(f(b, a))
}.runTailRec
Expand Down
Loading

0 comments on commit 02c7e3e

Please sign in to comment.