Wonay
Wonay

Reputation: 1250

ZIO : How to compute only once?

I am using ZIO: https://github.com/zio/zio

in my build.sbt:

"dev.zio" %% "zio" % "1.0.0-RC9"

No matter what I tried, my results are always being computed each time I need them:

val t = Task {
  println(s"Compute")
  12
}

    val r = unsafeRun(for {
      tt1 <- t
      tt2 <- t
    } yield {
      tt1 + tt2
    })

    println(r)

For this example, the log look like :

Compute
Compute
24

I tried with Promise:


    val p = for {
      p <- Promise.make[Nothing, Int]
      _ <- p.succeed {
        println(s"Compute - P")
        48
      }
      r <- p.await
    } yield {
      r
    }

    val r = unsafeRun(for {
      tt1 <- p
      tt2 <- p
    } yield {
      tt1 + tt2
    })

And I get the same issue:

Compute - P
Compute - P
96

I tried with

    val p = for {
      p <- Promise.make[Nothing, Int]
      _ <- p.succeed(48)
      r <- p.await
    } yield {
      println(s"Compute - P")
      r
    }

first and I was thinking that maybe the pipeline is executed but not the value recomputed but I does not work either.

I would like to be able to compute asynchronously my values and be able to reuse them. I looked at How do I make a Scalaz ZIO lazy? but it does not work for me either.

Upvotes: 4

Views: 2246

Answers (2)

Karl Bielefeldt
Karl Bielefeldt

Reputation: 49118

ZIO has memoize, which should do essentially what you want. I don't have a way to test it just now, but it should work something like:

for {
  memoized <- t.memoize
  tt1 <- memoized
  tt2 <- memoized
} yield tt1 + tt2

Note that unless the second and third lines of your real code have some branching that might result in the Task never getting called, or getting called only once, this yields the same answer and side effects as the much simpler:

t flatMap {tt => tt + tt}

Upvotes: 7

Jasper-M
Jasper-M

Reputation: 15086

Does computing the results have side effects? If it doesn't you can just use a regular old lazy val, perhaps lifted into ZIO.

lazy val results = computeResults()
val resultsIO = ZIO.succeedLazy(results)

If it does have side effects, you can't really cache the results because that wouldn't be referentially transparent, which is the whole point of ZIO. What you'll probably have to do is flatMap on your compute Task and write the rest of your program which needs the result of that computation inside that call to flatMap, threading the result value as a parameter through your function calls where necessary.

val compute = Task {
  println(s"Compute")
  12
}

compute.flatMap { result =>
  // the rest of your program
}

Upvotes: 4

Related Questions