diff --git a/free/src/main/scala/cats/free/FreeT.scala b/free/src/main/scala/cats/free/FreeT.scala index caa8b9e69d..7cf0dcc9e6 100644 --- a/free/src/main/scala/cats/free/FreeT.scala +++ b/free/src/main/scala/cats/free/FreeT.scala @@ -32,6 +32,19 @@ sealed abstract class FreeT[S[_], M[_], A] extends Product with Serializable { Suspend(mn(m)) } + /** + * Modify the context `M` using the transformation `mn`, flattening the free + * suspensions into the outer. + */ + def flatMapK[N[_]](mn: M ~> FreeT[S, N, *])(implicit S: Functor[S], N: Monad[N]): FreeT[S, N, A] = { + def loop(ftft: FreeT[S, FreeT[S, N, *], A]): FreeT[S, N, A] = + ftft.resume.flatMap { e => + e.fold(sft => FreeT.liftF[S, N, FreeT[S, FreeT[S, N, *], A]](sft).flatMap(loop(_)), a => FreeT.pure(a)) + } + + loop(mapK(mn)) + } + /** Binds the given continuation to the result of this computation. */ final def flatMap[B](f: A => FreeT[S, M, B]): FreeT[S, M, B] = FlatMapped(this, f)