3

我正在使用 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
    }

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

我希望能够异步计算我的值并能够重用它们。我查看了如何使 Scalaz ZIO 变得懒惰?但这对我也不起作用。

4

2 回答 2

4

计算结果有副作用吗?如果不是,您可以只使用常规的旧惰性 val,也许提升到ZIO.

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

如果它确实有副作用,你就不能真正缓存结果,因为那不会是引用透明的,这就是ZIO. 您可能需要做的是flatMap在您的计算上Task编写程序的其余部分,该程序需要在该调用中计算该计算的结果,并在必要时通过您的函数调用将值作为参数flatMap线程化。result

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

compute.flatMap { result =>
  // the rest of your program
}
于 2019-07-09T08:50:55.767 回答
4

ZIO 有memoize,它基本上应该做你想做的事。我现在没有办法测试它,但它应该像这样工作:

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

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

t flatMap {tt => tt + tt}
于 2019-07-10T01:23:54.023 回答