object SessionTypes { final class Eps { } final class Send[a, r] { } final class Recv[a, r] { } final class Choose[r, s] { } final class Offer[r, s] { } final object Dual { val eps = new Dual[Eps, Eps] } final class Dual[r, s] private extends scala.NotNull { def send[a] = new Dual[Send[a, r], Recv[a, s]] def recv[a] = new Dual[Recv[a, r], Send[a, s]] def choose[r2, s2] = new Dual[Offer[r, r2], Choose[s, s2]] def offer[r2, s2] = new Dual[Offer[r, r2], Choose[s, s2]] def dual = new Dual[s, r] } val eps = Dual.eps final object Session { def ret[s, a](a: a) = new Session[s, s, a] (() => a) def send[a, s](a: a) = new Session[Send[a, s], s, Unit] (() => ()) def recv[a, s] = new Session[Recv[a, s], s, a] (() => throw new Exception) def mock_recv[a, s](a: a) = new Session[Recv[a, s], s, a] (() => a) def sel1[r, s] = new Session[Choose[r, s], r, Unit] (() => ()) def sel2[r, s] = new Session[Choose[r, s], s, Unit] (() => ()) def cases[r, s, u, a](left: Session[r, u, a], right: Session[s, u, a]) = new Session[Offer[r, s], u, a] (() => left.act) def close = new Session[Eps, Unit, Unit](() => ()) def run[r, s, a](witness: Dual[s, r], r: Session[r, Unit, Unit], s: Session[s, Unit, a]) = { r.act; s.act } } final class Session[s, t, a] private (action: () => a) { private def act = action.apply def >>[u, b](next: a => Session[t, u, b]) = new Session[s, u, b](() => next(act).act) def >>[u, b](next: Session[t, u, b]) = new Session[s, u, b](() => { act; next.act }) } } object Example { import SessionTypes._; import Session._; var proto = eps.recv[String].send[Int] var mock_server = mock_recv(8) >> ((x: Int) => (send(x.toString) >> close)) def mock_client(i: Int) = send(i) >> (mock_recv("8") >> ((s: String) => (close >> ret[Unit, String](s)))) var server = recv >> ((x: Int) => (send(x.toString) >> close)) def client(i: Int) = send(i) >> (recv >> ((s: String) => (close >> ret[Unit, String](s)))) def main(s: Array[String]) = run(proto, mock_server, mock_client(5)) }