Scala类型推理混乱

时间:2018-08-22 19:26:08

标签: scala

  trait IO[F[_], +A]
  case class Pure[F[_], +A](get: A) extends IO[F,A]
  case class Request[F[_], I, +A](expr: F[I], receive: I => IO[F,A]) extends IO[F,A]

  trait Console[A]
  case object ReadLine extends Console[Option[String]]
  case class PrintLine(s: String) extends Console[Unit]

  trait Run[F[_]] {
    def apply[A](expr: F[A]): (A, Run[F])
  }

  object IO {
    @annotation.tailrec
    def run[F[_],A](R: Run[F])(io: IO[F,A]): A = io match {
      case Pure(a) => a
      case Request(expr,recv) =>
        R(expr) match { case (e,r2) => println(e.getClass); run(r2)(recv(e)) }
    }
  }

代码来自“ Scala中的功能编程”,IDE抱怨模式匹配中的“ recv”应仅接收Nothing类型作为其参数,而实际上类型为Any。但是,它仍然可以通过编译。我还认为recv将被推断为run [F [?],A]函数的Request [F [?],Nothing,A]。这里发生了什么?看来Scala具有一些动态功能。它可能会推断运行时中的I类型,这是不正确的。

1 个答案:

答案 0 :(得分:1)

根据Request的定义,我们知道expr的类型为F[I],而recv的类型为I => IO[F, A]。根据{{​​1}}的定义,我们知道Run的类型为R(expr)。因此(I, Run[F])的类型为e,而I是一个接受类型为recv的参数的函数。

这告诉我们I的类型正确,即使我们对recv(e)一无所知。

  

我还认为recv将被推断为run [F [?],A]函数的Request [F [?],Nothing,A]。

否,I的类型为recv,其中I => IO[F, A]FA定义中的类型变量,而run是其中的一个创建I对象时,type被用作Request的第二个类型参数。