ЗИО: Как рассчитать только один раз?

Я использую 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 ответа

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

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

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

t flatMap {tt => tt + tt}

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