0

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)
 }
asked Dec 24, 2021 at 17:42

1 Answer 1

1

I'm not sure why you choose to define your services this way but if your question is to avoid calling run in sumAndShow you could lift your Reader/IO into ReaderTs 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

Alternative generic implementation with existing typeclass constraints with Cats/Cats Effect, and also how newtype could be used for alternative typeclass instances:

import cats.implicits._
import cats.effect._
import cats.effect.std.Console
import cats.{Semigroup, Show}
import io.estatico.newtype.macros.newtype
object Main extends IOApp {
 @newtype case class MInt(value: Int)
 object MInt {
 implicit val multiplicativeSemigroup: Semigroup[MInt] =
 deriving(Semigroup.instance(_ * _))
 implicit val show: Show[MInt] = deriving
 }
 def sumAndShow[F[_]: Console, A: Show: Semigroup](a: A, b: A): F[Unit] =
 Console[F].println(a |+| b)
 override def run(args: List[String]): IO[ExitCode] =
 for {
 _ <- sumAndShow[IO, Int](10, 10) //20
 //you can also "inject" default/custom typeclass "dependencies" explicitly
 _ <- sumAndShow[IO, Int](10, 10)(Console[IO], Show[Int], Semigroup.instance(_ * _)) //100
 //custom typeclass instance with newtype
 _ <- sumAndShow[IO, MInt](MInt(10), MInt(10)) //100
 _ <- sumAndShow[IO, String]("Hello", "World") //HelloWorld
 } yield ExitCode.Success
}
answered Dec 24, 2021 at 18:58

6 Comments

Thank's a lot. I didn't define the services that way for no special reason but since you mentioned that, what's the best way specify several dependencies including dependencies that are shared by several components?
Firstly, Reader[Dependencies, IO[Int]] is really awkward type which could have been easily refactored to ReaderT[IO, Dependencies, Int] or Reader[Dependencies, Int]. I understand that you want generic implementation for your services but it kind of forces your sum to be unnecessarily wrapped in an IO and depend on Dependencies where it could have just return an Int and get lifted into a ReaderT when needed.
You should look into Show and Console typeclasses in Cats/Cats Effect. Wrapping services in case classes is fine but you don't need to view everything as a service if all you need is to do things generically. To have multiple typeclasses instances for the same types you can encode them as new types. Here's an example: stackoverflow.com/questions/68569306/…
Then when you comfortable with typeclass constraints you can read up on "tagless final" and MTL.
I've added an example where ShowService is replaced by Console and Show, and SumService is replaced by Semigroup.
|

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.