From 2de5d6b8f0de30b457d11e98332a90e9a135df15 Mon Sep 17 00:00:00 2001 From: Travis Brown Date: Tue, 25 Oct 2016 19:21:46 -0500 Subject: [PATCH 1/2] Use FunctionK instead of ~> alias in FreeT --- free/src/main/scala/cats/free/FreeT.scala | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/free/src/main/scala/cats/free/FreeT.scala b/free/src/main/scala/cats/free/FreeT.scala index 3024ef930e..896051dece 100644 --- a/free/src/main/scala/cats/free/FreeT.scala +++ b/free/src/main/scala/cats/free/FreeT.scala @@ -3,6 +3,8 @@ package free import scala.annotation.tailrec +import cats.arrow.FunctionK + /** * FreeT is a monad transformer for Free monads over a Functor S * @@ -27,7 +29,7 @@ sealed abstract class FreeT[S[_], M[_], A] extends Product with Serializable { * Changes the underlying `Monad` for this `FreeT`, ie. * turning this `FreeT[S, M, A]` into a `FreeT[S, N, A]`. */ - def hoist[N[_]](mn: M ~> N): FreeT[S, N, A] = + def hoist[N[_]](mn: FunctionK[M, N]): FreeT[S, N, A] = step match { case e @ FlatMapped(_, _) => FlatMapped(e.a.hoist(mn), e.f.andThen(_.hoist(mn))) @@ -36,7 +38,7 @@ sealed abstract class FreeT[S[_], M[_], A] extends Product with Serializable { } /** Change the base functor `S` for a `FreeT` action. */ - def interpret[T[_]](st: S ~> T)(implicit M: Functor[M]): FreeT[T, M, A] = + def interpret[T[_]](st: FunctionK[S, T])(implicit M: Functor[M]): FreeT[T, M, A] = step match { case e @ FlatMapped(_, _) => FlatMapped(e.a.interpret(st), e.f.andThen(_.interpret(st))) @@ -48,7 +50,7 @@ sealed abstract class FreeT[S[_], M[_], A] extends Product with Serializable { * Runs to completion, mapping the suspension with the given transformation * at each step and accumulating into the monad `M`. */ - def foldMap(f: S ~> M)(implicit M: Monad[M]): M[A] = { + def foldMap(f: FunctionK[S, M])(implicit M: Monad[M]): M[A] = { def go(ft: FreeT[S, M, A]): M[Either[FreeT[S, M, A], A]] = ft match { case Suspend(ma) => M.flatMap(ma) { @@ -170,13 +172,13 @@ object FreeT extends FreeTInstances { def roll[S[_], M[_], A](value: S[FreeT[S, M, A]])(implicit M: Applicative[M]): FreeT[S, M, A] = liftF[S, M, FreeT[S, M, A]](value).flatMap(identity) - def interpret[S[_], T[_], M[_]: Functor](st: S ~> T): FreeT[S, M, ?] ~> FreeT[T, M, ?] = - new ~>[FreeT[S, M, ?], FreeT[T, M, ?]] { + def interpret[S[_], T[_], M[_]: Functor](st: FunctionK[S, T]): FunctionK[FreeT[S, M, ?], FreeT[T, M, ?]] = + new FunctionK[FreeT[S, M, ?], FreeT[T, M, ?]] { def apply[A](f: FreeT[S, M, A]) = f.interpret(st) } - def foldMap[S[_], M[_]: Monad](fk: S ~> M): FreeT[S, M, ?] ~> M = - new ~>[FreeT[S, M, ?], M] { + def foldMap[S[_], M[_]: Monad](fk: FunctionK[S, M]): FunctionK[FreeT[S, M, ?], M] = + new FunctionK[FreeT[S, M, ?], M] { def apply[A](f: FreeT[S, M, A]) = f.foldMap(fk) } } From f93a5789c6fad00441a76f50b3a994202d18c963 Mon Sep 17 00:00:00 2001 From: Travis Brown Date: Tue, 25 Oct 2016 19:31:11 -0500 Subject: [PATCH 2/2] Rename interpret in FreeT to compile for consistency with Free --- free/src/main/scala/cats/free/FreeT.scala | 11 +++++++---- free/src/test/scala/cats/free/FreeTTests.scala | 10 +++++----- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/free/src/main/scala/cats/free/FreeT.scala b/free/src/main/scala/cats/free/FreeT.scala index 896051dece..44fd32a053 100644 --- a/free/src/main/scala/cats/free/FreeT.scala +++ b/free/src/main/scala/cats/free/FreeT.scala @@ -37,11 +37,14 @@ sealed abstract class FreeT[S[_], M[_], A] extends Product with Serializable { Suspend(mn(m)) } + @deprecated("Use compile", "0.8.0") + def interpret[T[_]](st: FunctionK[S, T])(implicit M: Functor[M]): FreeT[T, M, A] = compile(st) + /** Change the base functor `S` for a `FreeT` action. */ - def interpret[T[_]](st: FunctionK[S, T])(implicit M: Functor[M]): FreeT[T, M, A] = + def compile[T[_]](st: FunctionK[S, T])(implicit M: Functor[M]): FreeT[T, M, A] = step match { case e @ FlatMapped(_, _) => - FlatMapped(e.a.interpret(st), e.f.andThen(_.interpret(st))) + FlatMapped(e.a.compile(st), e.f.andThen(_.compile(st))) case Suspend(m) => Suspend(M.map(m)(_.left.map(s => st(s)))) } @@ -172,9 +175,9 @@ object FreeT extends FreeTInstances { def roll[S[_], M[_], A](value: S[FreeT[S, M, A]])(implicit M: Applicative[M]): FreeT[S, M, A] = liftF[S, M, FreeT[S, M, A]](value).flatMap(identity) - def interpret[S[_], T[_], M[_]: Functor](st: FunctionK[S, T]): FunctionK[FreeT[S, M, ?], FreeT[T, M, ?]] = + def compile[S[_], T[_], M[_]: Functor](st: FunctionK[S, T]): FunctionK[FreeT[S, M, ?], FreeT[T, M, ?]] = new FunctionK[FreeT[S, M, ?], FreeT[T, M, ?]] { - def apply[A](f: FreeT[S, M, A]) = f.interpret(st) + def apply[A](f: FreeT[S, M, A]) = f.compile(st) } def foldMap[S[_], M[_]: Monad](fk: FunctionK[S, M]): FunctionK[FreeT[S, M, ?], M] = diff --git a/free/src/test/scala/cats/free/FreeTTests.scala b/free/src/test/scala/cats/free/FreeTTests.scala index 617d0c1bd0..95b8e127b3 100644 --- a/free/src/test/scala/cats/free/FreeTTests.scala +++ b/free/src/test/scala/cats/free/FreeTTests.scala @@ -101,20 +101,20 @@ class FreeTTests extends CatsSuite { val d: FreeT[JustFunctor, JustFunctor, Int] = transLiftInstance.liftT[JustFunctor, Int](JustFunctor(1)) } - test("interpret to universal id equivalent to original instance") { + test("compile to universal id equivalent to original instance") { forAll { a: FreeTOption[Int] => - val b = a.interpret(FunctionK.id) + val b = a.compile(FunctionK.id) Eq[FreeTOption[Int]].eqv(a, b) should ===(true) - val fk = FreeT.interpret[Option, Option, Option](FunctionK.id) + val fk = FreeT.compile[Option, Option, Option](FunctionK.id) a should === (fk(a)) } } - test("interpret stack-safety") { + test("compile stack-safety") { val a = (0 until 50000).foldLeft(Applicative[FreeTOption].pure(()))( (fu, i) => fu.flatMap(u => Applicative[FreeTOption].pure(u)) ) - val b = a.interpret(FunctionK.id) // used to overflow + val b = a.compile(FunctionK.id) // used to overflow } test("foldMap consistent with runM") {