ZIO : How to compute only once?

百般思念 提交于 2019-12-24 00:44:01

问题


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.


回答1:


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
}



回答2:


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}


来源:https://stackoverflow.com/questions/56944089/zio-how-to-compute-only-once

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!