So i started to learn free monadic approach in my code style recently, and i hope i get the main idea of it. We have our own dsl to build a program, then we pass a compiler to a real world effect such as cats.IO and it looks good in simple programs such as calculator or smth but when i tried to build a real world app, such as http server with multiple domains (Postgress adt: get, post, delete, update. Config adt: read. HttpServer adt: start) and many more, i can't understand, how to compose a program with multiple dsls.
cats off doc says to try (type CatsApp[A] = EitherK[DataOp, Interact, A]) which is kind of a thing i've been looking for, but so far it only says how to compose 2 compilers into 1.
i either need a solution to compose any amount compilers or i have to build a huge ass adt which can do anything
object ConfigADT {
type Config[A] = Free[ConfigA, A]
sealed trait ConfigA[A]
case class Read[T]() extends ConfigA[T]
def read[A]: Config[A] = liftF[ConfigA, A](Read[A]())
}
object ServerADT {
type Server[A] = Free[ServerA, A]
sealed trait ServerA[A]
case class Start[T, C](config: C) extends ServerA[T]
def start[A, C](config: C): Server[A] = liftF[ServerA, A](Start[A, C](config))
}
object VictoriaMetricsADT {
type VictoriaMetrics[T] = Free[VictoriaMetricsA, T]
sealed trait VictoriaMetricsA[T]
case class Query[T, C](query: String)(config: C) extends VictoriaMetricsA[T]
case class Put[T, C](value: T)(config: C) extends VictoriaMetricsA[Unit]
def query[T, C](query: String)(config: C): VictoriaMetrics[T] = liftF[VictoriaMetricsA, T](Query[T, C](query)(config))
def put[T, C](value: T)(config: C): VictoriaMetrics[Unit] = liftF[VictoriaMetricsA, Unit](Put[T, C](value)(config))
}
i want to make a program which will read a config then start a server and server will use victoria dsl
for {
config <- ConfigADT.read[ConfigData]
dataFromVictoria <- VictoriaADT.query("my query")(config)
server <- ServerADT.start(config)
} yield ()
i understand, code is very abstract, but i hope i showed you the main idea what i'm trying to do.
i might not fully understood the concept of multiple programs combining into big one. I'm still thinking to compile some parts of it in the middle, so i can compose it using IO. Please help my stupid head
Yes, surely it's possible to compose multiple interpreters.
Your code corresponds to the section Free your ADT. But you should use written in the next section Composing Free monads ADTs, just not for
EitherK[Algebra1, Algebra2, A]but forEitherK[Algebra1, EitherK[Algebra2, Algebra3, *], A]https://medium.com/@olxc/the-evolution-of-a-scala-programmer-1b7a709fb71f#2de0