4

我是函数式编程和 Scala 的新手,我正在查看 Cats Effect 框架并试图了解 IO monad 的作用。到目前为止,我所理解的是,在 IO 块中编写代码只是对需要完成的操作的描述,并且在您使用unsafe提供的方法显式运行之前什么都不会发生,并且也是一种制作参考执行副作用的代码的方法实际上不运行它是透明的。

我尝试执行下面的代码片段只是为了理解它的含义:

object Playground extends App {
  var out = 10
  var state = "paused"

  def changeState(newState: String): IO[Unit] = {
    state = newState
    IO(println("Updated state."))
  }

  def x(string: String): IO[Unit] = {
    out += 1
    IO(println(string))
  }

  val tuple1 = (x("one"), x("two"))

  for {
    _ <- x("1")
    _ <- changeState("playing")
  } yield ()

  println(out)
  println(state)
}

输出是:

13
paused

我不明白为什么赋值state = newState不运行,但增量和赋值表达式out += 1运行。我是否遗漏了一些关于这应该如何工作的明显内容?我真的可以使用一些帮助。我知道我可以使用这些unsafe方法来运行它。

4

1 回答 1

4

在您的特定示例中,我认为正在发生的事情是常规的命令式 Scala 编码不受IOmonad 的影响——它在 Scala 规则下正常运行时运行。

当你运行时:

for {
  _ <- x("1")
  _ <- changeState("playing")
} yield ()

这立即调用xIO这与单子无关;这就是for理解的定义方式。第一步是评估第一个语句,以便您可以调用flatMap它。

正如您所观察到的,您永远不会“运行”一元结果,因此flatMap从不调用 的参数(一元延续),从而不会调用changeState。这是特定于IOmonad 的,例如,ListmonadflatMap会立即调用该函数(除非它是一个空列表)。

于 2020-12-10T05:38:58.823 回答