Skip to content

Instantly share code, notes, and snippets.

@lrodero
Last active November 17, 2024 19:37
Show Gist options
  • Select an option

  • Save lrodero/1d83edead347c06846ecd070fb6762dc to your computer and use it in GitHub Desktop.

Select an option

Save lrodero/1d83edead347c06846ecd070fb6762dc to your computer and use it in GitHub Desktop.
//> using scala 3.3.4
//> using dep org.typelevel::cats-core:2.12.0
//> using dep org.typelevel::cats-effect:3.5.5
// Code accompanying the blog entry 'Understanding Kleisli: using it to pass context info'
// at https://lrodero.hashnode.dev/understanding-kleisli-using-it-to-pass-context-info
// Run using scala-cli:
// $ scala-cli PassingContextUsingKleisli.scala
import cats.data.Kleisli
import cats.effect.std.Random
import cats.effect.{IO, IOApp}
import cats.syntax.all.*
import java.util.UUID
case class Context(traceId: UUID)
object UsingExplicitContext {
def generate(c: Context): IO[Int] =
IO.println(s"Trace ${c.traceId}") >> Random.scalaUtilRandom[IO] >>= (rg => rg.betweenInt(1, 101))
def processOdd(i: Int, c: Context): IO[Double] =
IO.println(s"Trace ${c.traceId}").as(i * 0.001)
def processEven(i: Int, c: Context): IO[Double] =
IO.println(s"Trace ${c.traceId}").as(i * 1000.0)
def writeResult(d: Double, c: Context): IO[Unit] =
IO.println(s"Trace ${c.traceId} final result = $d")
val program =
for {
c <- IO.randomUUID.map(Context.apply)
rand <- generate(c)
res <- if(rand % 2 == 0) processEven(rand, c) else processOdd(rand, c)
_ <- writeResult(res, c)
} yield ()
}
object UsingImplicitContext {
def generate(implicit c: Context): IO[Int] =
IO.println(s"Trace ${c.traceId}") >> Random.scalaUtilRandom[IO] >>= (rg => rg.betweenInt(1, 101))
def processOdd(i: Int)(implicit c: Context): IO[Double] =
IO.println(s"Trace ${c.traceId}").as(i * 0.001)
def processEven(i: Int)(implicit c: Context): IO[Double] =
IO.println(s"Trace ${c.traceId}").as(i * 1000.0)
def writeResult(d: Double)(implicit c: Context): IO[Unit] =
IO.println(s"Trace ${c.traceId} final result = $d")
val program =
IO.randomUUID.map(Context.apply) >>= { implicit context =>
for {
rand <- generate
res <- if (rand % 2 == 0) processEven(rand) else processOdd(rand)
_ <- writeResult(res)
} yield ()
}
}
object UsingKleisli {
val generate: Kleisli[IO, Context, Int] = Kleisli { (c: Context) =>
IO.println(s"Trace ${c.traceId}") >> Random.scalaUtilRandom[IO] >>= (rg => rg.betweenInt(1, 101))
}
def processOdd(i: Int): Kleisli[IO, Context, Double] = Kleisli { (c: Context) =>
IO.println(s"Trace ${c.traceId}") >> (i * 0.001).pure[IO]
}
def processEven(i: Int): Kleisli[IO, Context, Double] = Kleisli { (c: Context) =>
IO.println(s"Trace ${c.traceId}") >> (i * 1000.0).pure[IO]
}
def writeResult(d: Double): Kleisli[IO, Context, Unit] = Kleisli { (c: Context) =>
IO.println(s"Trace ${c.traceId} final result = $d")
}
val programK: Kleisli[IO, Context, Unit] = // Program as a Kleisli
for {
rand <- generate
res <- if(rand % 2 == 0) processEven(rand) else processOdd(rand)
_ <- writeResult(res)
} yield ()
val program: IO[Unit] = IO.randomUUID.map(Context.apply) >>= programK.run
}
object Main extends IOApp.Simple:
override val run: IO[Unit] =
UsingExplicitContext.program >> UsingImplicitContext.program >> UsingKleisli.program
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment