import cats.effect.IO import freestyle.free._ import freestyle.free.implicits._ @free trait Logger { def debug(message: String): FS[Unit] } @free trait Summer { def sum(a: Int, b: Int): FS[Int] } @module trait FreeApp { val log: Logger val summer: Summer def program[F[_]](a: Int, b: Int)(implicit app: FreeApp[F]): FreeS[F, Int] = for { sum <- app.summer.sum(a, b) _ <- app.log.debug(s"$a + $b = $sum") } yield sum } object FreeModulesExample extends App { implicit val loggerHandler = new Logger.Handler[IO] { def debug(message: String): IO[Unit] = IO { println(s"Logger debug: $message") } } implicit val summerHandler = new Summer.Handler[IO] { override def sum(a: Int, b: Int): IO[Int] = IO { a + b } } val result = FreeApp.instance.program[FreeApp.Op](5, 3).interpret[IO].unsafeRunSync() println(s"Result is: $result") // Logger debug: 5 + 3 = 8 // Result is: 8 }