I am using cats library and want to convert Free Monad to Free Applicative.
We have a lot of code in Free monads.. But now some parts of the application has to run in parallel. There are options to use Tagless or Frees.io instead of Free.. But that will be a huge change...
This is an example DSL:
sealed trait DSLAction[A]
case class GetCustomer(request: Boolean) extends DSLAction[String]
case class GetSize(request: Boolean) extends DSLAction[Int]
val f1: Free[DSLAction, String] = liftF(GetCustomer(true))
val f2: Free[DSLAction, Int] = liftF(GetSize(true))
val f3: Free[DSLAction, Int] = liftF(GetSize(false))
val interpreter: DSLAction ~> Id = {
λ[DSLAction ~> Id] {
case GetCustomer(_: Boolean) => {
"hello"
}
case GetSize(_: Boolean) => {
123
}
}
}
Cats library provides a way to convert FreeApplicative to Free monad using .monad()
However, I want to convert Free to FreeApplicative to use them in for comprehension
I want to define a method toApplicative () that does the job...
type FEF[A] = FreeApplicative[DSLAction, A]
val f1AP: FEF[String] = toApplicative(f1)
val f2AP: FEF[Int] = toApplicative(f2)
val prog = for {
a <- (f1AP, f2AP).mapN { case (l, r) => l + r }.monad
b <- f3
} yield {
(a, b)
}
prog.foldMap(interpreter)
I did try to implement something.. But not sure how to define flatMap and tailRec methods..
Or there may be another way
implicit val myConvertor = new Monad[FEF] {
override def pure[A](x: A): FEF[A] = FreeApplicative.pure[DSLAction,A](x)
override def flatMap[A, B](fa: FEF[A])(f: A => FEF[B]): FEF[B] = ???
override def tailRecM[A, B](a: A)(f: A => FEF[Either[A, B]]): FEF[B] = ???
}
final def toApplicative[F, A](free: Free[DSLAction, A]) =
free.foldMap[FreeApplicative[DSLAction, ?]] {
λ[FunctionK[DSLAction, FEF]](fa => FreeApplicative.lift(fa))
}
Thanks