From e799fd031bda1c42d9b5f68f93f7d1d790e543b6 Mon Sep 17 00:00:00 2001 From: Sumedh Mungee Date: Thu, 15 Oct 2015 15:11:52 -0700 Subject: [PATCH] Add FreeApplicative.analyze In trying to port the FreeApplicative example from @jdegoes's ScalaWorld 2015 talk[1] to cats, I found that cats does not have a FreeApplicative.analyze method, which allows us to compile a FreeApplicative into a monoid. This commit adds FreeApplicative.analyze, as well as a new test for this, as per a discussion on gitter [2]. [1] https://github.com/jdegoes/scalaworld-2015/blob/master/src/main/scala/asmfree.scala#L32 [2] https://gitter.im/non/cats?at=561ed5373a0d354869528194 --- .../src/main/scala/cats/free/FreeApplicative.scala | 7 +++++++ .../scala/cats/free/FreeApplicativeTests.scala | 14 ++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/free/src/main/scala/cats/free/FreeApplicative.scala b/free/src/main/scala/cats/free/FreeApplicative.scala index 399ae67eaf..5766ec867e 100644 --- a/free/src/main/scala/cats/free/FreeApplicative.scala +++ b/free/src/main/scala/cats/free/FreeApplicative.scala @@ -2,6 +2,7 @@ package cats package free import cats.arrow.NaturalTransformation +import cats.data.Const /** Applicative Functor for Free */ sealed abstract class FreeApplicative[F[_], A] extends Product with Serializable { self => @@ -46,6 +47,12 @@ sealed abstract class FreeApplicative[F[_], A] extends Product with Serializable } } + /** Interpret this algebra into a Monoid */ + def analyze[M:Monoid](f: F ~> λ[α => M]): M = + foldMap[Const[M, ?]](new (F ~> Const[M, ?]) { + def apply[X](x: F[X]): Const[M,X] = Const(f(x)) + }).getConst + /** Compile this FreeApplicative algebra into a Free algebra. */ final def monad: Free[F, A] = foldMap[Free[F, ?]] { diff --git a/free/src/test/scala/cats/free/FreeApplicativeTests.scala b/free/src/test/scala/cats/free/FreeApplicativeTests.scala index e8308ccaae..7084d90bc7 100644 --- a/free/src/test/scala/cats/free/FreeApplicativeTests.scala +++ b/free/src/test/scala/cats/free/FreeApplicativeTests.scala @@ -4,6 +4,7 @@ package free import cats.arrow.NaturalTransformation import cats.laws.discipline.{ArbitraryK, ApplicativeTests, SerializableTests} import cats.tests.CatsSuite +import cats.data.Const import org.scalacheck.{Arbitrary, Gen} @@ -75,4 +76,17 @@ class FreeApplicativeTests extends CatsSuite { val fli2 = FreeApplicative.lift[List, Int](List(1, 3, 5, 7)) (fli1 |@| fli2).map(_ + _) } + + test("FreeApplicative#analyze") { + type G[A] = List[Int] + val countingNT = new NaturalTransformation[List, G] { + def apply[A](la: List[A]): G[A] = List(la.length) + } + + val fli1 = FreeApplicative.lift[List, Int](List(1, 3, 5, 7)) + fli1.analyze[G[Int]](countingNT) should === (List(4)) + + val fli2 = FreeApplicative.lift[List, Int](List.empty) + fli2.analyze[G[Int]](countingNT) should ===(List(0)) + } }