scalaz MVar take 方法无限阻塞

scalaz MVar take method blocks infinitely

我是 scalaz 的新手,我想探索 MVar 的用法。所以我做了一个小脚本:

object MVarThingy {

  val haha = newEmptyMVar[Int]

  def forkIO(f: => IO[Unit])(implicit s: Strategy): IO[Unit] = IO {
    s(f.unsafePerformIO)
  }

  def writeDelay(v: MVar[Int]): IO[Unit] = for {
    _ <- IO(println("wait to put value to haha"))
    _ <- IO(Thread.sleep(5000))
    _ <- IO(println("now put value to haha"))
    _ <- v.put(42)
  } yield ()

  def writeNow(v: MVar[Int]): IO[Unit] = v.put(24)

  def takeHaha: IO[Int] = for {
    v <- haha
    _ <- IO(println("try to get haha.."))
    a <- v.take
  } yield a

  def run(): Unit = {
    val blah = for {
      mvar <- haha
      _ <- forkIO(writeDelay(mvar))
      a <- takeHaha
    } yield a

    println("value in mvar is: " + blah.unsafePerformIO)
  }
}

如果我运行MVarThingy.run,它会无限阻塞。

但是,如果我将 takeHaharun 更改为

  def takeHaha(v: MVar[Int]): IO[Int] = for {
    _ <- IO(println("try to get haha.."))
    a <- v.take
  } yield a

  def run(): Unit = {
    val blah = for {
      mvar <- haha
      _ <- forkIO(writeDelay(mvar))
      a <- takeHaha(mvar)
    } yield a

    println("value in mvar is: " + blah.unsafePerformIO)
  }

然后一切如我所愿,输入值后,将取值,程序将正常终止。

能否解释一下为什么会有这样的差异?

我刚刚发现 newEmptyMVar[A] 会产生 IO[MVar[A]],而 IO[A] 是懒惰的。

在第一种情况下,我得到两个不同的 MVar