Skip to content

Instantly share code, notes, and snippets.

@seigert
Last active November 20, 2023 17:08
Show Gist options
  • Select an option

  • Save seigert/cf53a0e641a38ab57dfa2aa4e4f4c02f to your computer and use it in GitHub Desktop.

Select an option

Save seigert/cf53a0e641a38ab57dfa2aa4e4f4c02f to your computer and use it in GitHub Desktop.

Revisions

  1. seigert revised this gist Nov 20, 2023. 1 changed file with 19 additions and 22 deletions.
    41 changes: 19 additions & 22 deletions Res.scala
    Original file line number Diff line number Diff line change
    @@ -43,37 +43,34 @@ object B:
    Random.scalaUtilRandom[F].map(new B(res, _))

    object HelloWorld extends IOApp.Simple:
    def exec(r: Res[IO], name: String) =
    r.execute.flatMap(out => IO.println(s"$name: $out")).replicateA(2)

    val run: IO[Unit] = for
    a <- A[IO]
    aOut <- a.execute
    _ <- IO.println(aOut)
    _ <- exec(a, "Random A")
    b <- B[IO](a)
    bOut <- b.execute
    _ <- IO.println(bOut)
    _ <- exec(b, "Random B")
    mA <- MemoRes(a)
    mAOut <- mA.execute
    _ <- IO.println(mAOut)
    _ <- exec(mA, "Memo A")
    bMA <- B[IO](mA)
    bMAOut1 <- bMA.execute
    bMAOut2 <- bMA.execute
    _ <- IO.println(bMAOut1)
    _ <- IO.println(bMAOut2)
    _ <- exec(bMA, "Memo A, Random B")
    mB <- MemoRes(bMA)
    mBOut1 <- mB.execute
    mBOut2 <- mB.execute
    _ <- IO.println(mBOut1)
    _ <- IO.println(mBOut2)
    _ <- exec(mB, "Memo A, Memo B")
    yield ()

    /* Example output:
    $> scala-cli Resource.scala
    $> scala-cli Resource.scala
    Compiling project (Scala 3.3.1, JVM)
    Compiled project (Scala 3.3.1, JVM)
    Output(1615723627) // A value is random
    Output(-1404996787 and then 29602411) // both A and B values are random
    Output(-1537149269) // A value is memoized
    Output(-1537149269 and then 1347641802) // A value is memoized, B value is random
    Output(-1537149269 and then -1281823817) // A value is memoized, B value is random
    Output(-1537149269 and then -185637696) // both A and B values are memoized
    Output(-1537149269 and then -185637696) // both A and B values are random
    Random A: Output(-1900047113)
    Random A: Output(-2043093384)
    Random B: Output(-97920439 and then -1453735903)
    Random B: Output(740318208 and then -1538324097)
    Memo A: Output(-120078346)
    Memo A: Output(-120078346)
    Memo A, Random B: Output(-120078346 and then -652810765)
    Memo A, Random B: Output(-120078346 and then -1886247155)
    Memo A, Memo B: Output(-120078346 and then -1758247976)
    Memo A, Memo B: Output(-120078346 and then -1758247976)
    */
  2. seigert created this gist Nov 20, 2023.
    79 changes: 79 additions & 0 deletions Res.scala
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,79 @@
    //> using scala "3.3.1"

    //> using option "-new-syntax"
    //> using option "-Ykind-projector:underscores"

    //> using lib "org.typelevel::cats-effect::3.5.2"

    import cats._
    import cats.effect._
    import cats.effect.std.Random
    import cats.effect.syntax.all._
    import cats.syntax.all._

    final case class Output(s: String)

    sealed trait Res[F[_]]:
    def execute: F[Output]

    sealed trait MemoRes[F[_]] extends Res[F]

    object MemoRes:
    def apply[F[_]: Async](res: Res[F]): F[MemoRes[F]] =
    res.execute.memoize.map: fa =>
    new MemoRes[F]:
    val execute: F[Output] = fa

    final class A[F[_]: Functor](rnd: Random[F]) extends Res[F]:
    val execute: F[Output] =
    rnd.nextInt.map: i =>
    Output(i.toString)

    object A:
    def apply[F[_]: Sync]: F[A[F]] =
    Random.scalaUtilRandom[F].map(new A(_))

    final class B[F[_]: Applicative](res: Res[F], rnd: Random[F]) extends Res[F]:
    val execute: F[Output] =
    (res.execute, rnd.nextInt).mapN: (out, i) =>
    Output(s"${out.s} and then $i")

    object B:
    def apply[F[_]: Sync](res: Res[F]): F[B[F]] =
    Random.scalaUtilRandom[F].map(new B(res, _))

    object HelloWorld extends IOApp.Simple:
    val run: IO[Unit] = for
    a <- A[IO]
    aOut <- a.execute
    _ <- IO.println(aOut)
    b <- B[IO](a)
    bOut <- b.execute
    _ <- IO.println(bOut)
    mA <- MemoRes(a)
    mAOut <- mA.execute
    _ <- IO.println(mAOut)
    bMA <- B[IO](mA)
    bMAOut1 <- bMA.execute
    bMAOut2 <- bMA.execute
    _ <- IO.println(bMAOut1)
    _ <- IO.println(bMAOut2)
    mB <- MemoRes(bMA)
    mBOut1 <- mB.execute
    mBOut2 <- mB.execute
    _ <- IO.println(mBOut1)
    _ <- IO.println(mBOut2)
    yield ()

    /* Example output:
    $> scala-cli Resource.scala
    Compiling project (Scala 3.3.1, JVM)
    Compiled project (Scala 3.3.1, JVM)
    Output(1615723627) // A value is random
    Output(-1404996787 and then 29602411) // both A and B values are random
    Output(-1537149269) // A value is memoized
    Output(-1537149269 and then 1347641802) // A value is memoized, B value is random
    Output(-1537149269 and then -1281823817) // A value is memoized, B value is random
    Output(-1537149269 and then -185637696) // both A and B values are memoized
    Output(-1537149269 and then -185637696) // both A and B values are random
    */