Is there a way to avoid calling the "run" method twice and doing it just once from the main method or this is the right way to do it in nested Readers?
case class Dependencies(showService: ShowService, sumService: SumService)
class ShowService {
def show(s: String): IO[Unit] = IO {println(s)}
}
class SumService() {
def sum(a: Int, b: Int): Reader[Dependencies, IO[Int]] = Reader {_ => IO {a b} }
}
object ModuleA {
def sumAndShow: ReaderT[IO, Dependencies, Unit] = for {
x <- ReaderT[IO, Dependencies, Int] (deps => deps.sumService.sum(10, 10).run(deps))
r <- ReaderT[IO, Dependencies, Unit] (deps => deps.showService.show(x.toString))
} yield r
}
override def run(args: List[String]): IO[ExitCode] = {
val dependencies = Dependencies(new ShowService, new SumService)
ModuleA.sumAndShow.run(dependencies) *> IO(ExitCode.Success)
}
CodePudding user response:
I'm not sure why you choose to define you services this way but if your question is to avoid calling run
in sumAndShow
you could lift your Reader
/IO
into ReaderT
s with lift
/liftF
and compose them with a ReaderT.ask
:
def sumAndShow: ReaderT[IO, Dependencies, Unit] =
for {
deps <- ReaderT.ask[IO, Dependencies]
x <- deps.sumService.sum(10, 10).lift[IO].flatMap(ReaderT.liftF)
r <- ReaderT.liftF(deps.showService.show(x.toString))
} yield r