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)) } } } The code is from "Functional Programming in Scala", the IDE complains that "recv" from the pattern matching should only receive Nothing type as its argument, but actually type is Any. However, it still pass the compile. I also think recv will be inferenced as Request[F[?], Nothing, A] for the run[F[?], A] function. What happened here? It seems like Scala has some dynamic features. It could infer the I type in the runtime which is not true.