ЗИО: Как рассчитать только один раз? - PullRequest
2 голосов
/ 09 июля 2019

Я использую 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 ленивым? но у меня это тоже не работает.

Ответы [ 2 ]

4 голосов
/ 09 июля 2019

Есть ли у результатов вычисления побочные эффекты? Если это не так, вы можете просто использовать обычный старый ленивый 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
}
3 голосов
/ 10 июля 2019

ZIO имеет памятка , которая должна делать то, что вы хотите.У меня нет способа проверить это только сейчас, но он должен работать примерно так:

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

Обратите внимание, что если во второй и третьей строках вашего реального кода нет ветвления, которое может привести к Task никогда не вызывается или не вызывается только один раз, это дает тот же ответ и побочные эффекты, что и намного проще:

t flatMap {tt => tt + tt}
...