我正在试验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
为什么呢?有什么区别?
答案 0 :(得分:4)
你刚刚对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