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)) }
}
}