【问题标题】:Describe a computation描述一个计算
【发布时间】:2019-09-22 07:45:34
【问题描述】:

我有以下代码,我想知道为什么变量 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()
  }

}

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

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

【问题讨论】:

  • 我找不到Random.between
  • 请注意,如果它返回相同的值,则会破坏引用透明度,这是首先引入IO 的唯一原因。另外,您的 prints 是错误的,所有效果都必须暂停在 IO 内。

标签: scala functional-programming io-monad


【解决方案1】:

有区别

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()) 之间的区别非常相似。

【讨论】:

  • 计算和评估有什么区别?
  • 让我们使用 evaluation 将表达式替换为其值。让我们使用 computation 作为 IO 类型值的通用名称,因为在 strings 中是 String 类型的值。
【解决方案2】:

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 如何在内部将计算存储为() =&gt; Random.nextInt,然后使用run 方法实际评估计算f

同样,IO.apply 接受名为 : =&gt; A 的参数并最终构造 Delay 对象,该对象将未评估的计算存储在字段中作为 () =&gt; A,然后使用 unsafeRunSync 实际评估计算。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-03-16
    • 1970-01-01
    • 2019-06-29
    • 2021-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-07
    相关资源
    最近更新 更多