描述一个计算

Describe a computation

我有以下代码,我想知道为什么变量 number 被计算两次:

import cats.effect.IO

import scala.util.Random

object Main {

  private val number: IO[Int] =
    IO(Random.between(3, 300))

  def main(args: Array[String]): Unit = {


    number
      .flatMap { e =>
        println(e);
        number
      }.flatMap { e =>
      println(e);
      IO.unit
    }.unsafeRunSync()
  }

}

该程序打印两个不同的数字,尽管该数字是一个赋值。我知道在这里,我描述的是计算而不是执行,在宇宙的尽头,我 运行 程序。

问题是,为什么打印出两个不同的数字?

有区别

private val number: IO[Int] = IO(Random.nextInt())

private val number2: Int = Random.nextInt()

number 是一个计算随机数的值。当多次评估时,此类型 IO 的值(又名此计算)是 运行 多次,导致多个不同的随机数。

number2 计算时只是一个数字。

这与lambda(val lambda = () => Random.nextInt())和值(val value = Random.nextInt())之间的区别非常相似。

IO有点类似下面的场景

final case class SuspendedComputation[T](f: () => T) {
  def run: T = f()
}

val v = SuspendedComputation(Random.nextInt)
v.run
v.run

输出类似于

v: SuspendedComputation[Int] = SuspendedComputation(<function>
res2: Int = -1062309211
res3: Int = 765640585

注意 SuspendedComputation 如何在内部将计算存储为 () => Random.nextInt,然后使用 run 方法实际计算计算 f

类似地,IO.apply accepts an argument by-name : => A and eventually constructs Delay 对象将未评估的计算存储在字段中作为 () => A,然后使用 unsafeRunSync 实际评估计算。