For-comprehension for io monad 什么都不打印

For-comprehension for io monad prints nothing

我正在试验 IO monad,这是我写的:

val io: IO[String] = "asdfasdf".pure[IO]

val i: IO[Unit] = for{
  str <- io
} yield {
  println(str).pure[IO]
}

i.unsafePerformIO() // Performing io ops

代码没有输出。以下代码依次按预期工作:

val io: IO[Unit] = "asdfasdf".pure[IO].flatMap(println(_).pure[IO])
io.unsafePerformIO() //prints asdfasdf

为什么?有什么区别?

您刚刚对 scala 遇到了一个巨大的烦恼:推断 Unit

for{
  str <- io
} yield {
  println(str).pure[IO]
}

这个表达式是一个 IO[IO[Unit]],但是因为你告诉 scala(通过值的类型)你想要一个 IO[Unit],它基本上将表达式转换为如下:

for{
  str <- io
} yield {
  println(str).pure[IO] // <-- this IO action is basically thrown away
  ()                    // <-- inserted a Unit return
}

旁白... 请注意,此转换似乎是可能的,因为 IO[A]A 中是不变的。如果将 IList 替换为 IO 而不是 List (其类型参数是协变的),也会发生同样的事情,在这种情况下片段不会编译

返回答案...

相反,你应该写成:

for {
  str <- io
  _   <- println(str).pure[IO]
}
yield ()

更多旁白...

我个人只使用 expr.pure[IO] 其中 expr 是一个纯表达式,我使用 IO(expr) 其中 expr 是副作用,所以我更喜欢:

for {
  str <- io
  _   <- IO(println(str))
}
yield ()

最后,请注意这等同于:

io >>= IO.putStrLn