ZIO:如何只计算一次?

时间:2019-07-09 00:49:05

标签: scala functional-programming scalaz-zio

我正在使用ZIO:https://github.com/zio/zio

在我的build.sbt中:

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

无论我尝试什么,每次需要它们时,都会一直在计算我的结果:

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

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

    println(r)

对于此示例,日志如下所示:

Compute
Compute
24

我尝试过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
    })

我遇到同样的问题:

Compute - P
Compute - P
96

我尝试过

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

首先,我在想也许执行了管道,但没有重新计算值,但我也不工作。

我希望能够异步计算我的值并能够重用它们。 我看着How do I make a Scalaz ZIO lazy?,但它对我也不起作用。

2 个答案:

答案 0 :(得分:4)

计算结果是否有副作用?如果不是这样,您可以仅使用常规的旧式val,也许可以将其提升为ZIO

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

如果确实有副作用,则您将无法真正缓存结果,因为这不会是参照透明的,这是ZIO的重点。 您可能需要做的是在您的计算flatMapTask,然后在需要调用flatMap的程序中编写需要该计算结果的其余程序,将{{ 1}}值作为参数通过您的函数调用进行。

result

答案 1 :(得分:3)

ZIO有memoize,它应该基本上可以完成您想要的操作。我暂时没有办法对其进行测试,但它的工作方式应类似于:

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

请注意,除非实际代码的第二行和第三行具有某些分支,可能导致Task永远不会被调用或仅被调用一次,否则产生的答案和副作用与简单得多的相同:

t flatMap {tt => tt + tt}