diff --git a/free/src/main/scala/cats/free/Free.scala b/free/src/main/scala/cats/free/Free.scala index c4e2233b7b6..49fe776b25c 100644 --- a/free/src/main/scala/cats/free/Free.scala +++ b/free/src/main/scala/cats/free/Free.scala @@ -135,12 +135,12 @@ sealed abstract class Free[S[_], A] extends Product with Serializable { * Run to completion, mapping the suspension with the given transformation at each step and * accumulating into the monad `M`. */ - final def foldMap[M[_]](f: NaturalTransformation[S,M])(implicit M: Monad[M]): M[A] = - step match { - case Pure(a) => M.pure(a) - case Suspend(s) => f(s) - case Gosub(c, g) => M.flatMap(c.foldMap(f))(cc => g(cc).foldMap(f)) - } + final def foldMap[M[_]](f: NaturalTransformation[S,M])(implicit M: MonadRec[M]): M[A] = + M.tailRecM(this)(_.step match { + case Pure(a) => M.pure(Xor.right(a)) + case Suspend(sa) => M.map(f(sa))(Xor.right) + case Gosub(c, g) => M.map(c.foldMap(f))(cc => Xor.left(g(cc))) + }) /** * Compile your Free into another language by changing the suspension functor diff --git a/free/src/test/scala/cats/free/FreeTests.scala b/free/src/test/scala/cats/free/FreeTests.scala index 5291c60d5c8..144273c3b08 100644 --- a/free/src/test/scala/cats/free/FreeTests.scala +++ b/free/src/test/scala/cats/free/FreeTests.scala @@ -51,7 +51,7 @@ class FreeTests extends CatsSuite { fa should === (Free.pure[Option, Int](n)) } - ignore("foldMap is stack safe") { + test("foldMap is stack safe") { trait FTestApi[A] case class TB(i: Int) extends FTestApi[Int]