【问题标题】:For-comprehension for io monad prints nothingFor-comprehension for io monad 什么也不打印
【发布时间】:2017-11-21 17:08:18
【问题描述】:

我正在试验 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 io scalaz


    【解决方案1】:

    你刚刚对 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(其类型参数是协变的),也会发生同样的事情,在这种情况下,sn-p 将无法编译

    回到答案...

    相反,你应该写:

    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-07-04
      • 1970-01-01
      • 2016-06-12
      • 1970-01-01
      • 2015-02-15
      • 1970-01-01
      • 1970-01-01
      • 2014-04-24
      相关资源
      最近更新 更多