Skip to content

Instantly share code, notes, and snippets.

@msiegenthaler
Last active August 29, 2015 13:58
Show Gist options
  • Save msiegenthaler/10280778 to your computer and use it in GitHub Desktop.
Save msiegenthaler/10280778 to your computer and use it in GitHub Desktop.
import scala.annotation.implicitNotFound
import scala.reflect._
object Protocol extends App {
def witness = null
sealed trait Action
sealed trait End extends Action
sealed trait Receive[Value, Next <: Action] extends Action
sealed trait Send[V, Next <: Action] extends Action {
type Value = V
}
sealed trait InternalChoice[A <: Action, B <: Action] extends Action
sealed trait ExternalChoice[A <: Action, B <: Action] extends Action
type :?:[Value, Next <: Action] = Receive[Value, Next]
type :!:[Value, Next <: Action] = Send[Value, Next]
type :%:[A <: Action, B <: Action] = InternalChoice[A, B]
type :&:[A <: Action, B <: Action] = ExternalChoice[A, B]
@implicitNotFound("Protocol violation: ${A} and ${B} are not dual (client/server)")
sealed trait Dual[A <: Action, B <: Action]
implicit object DualEnd extends Dual[End, End]
implicit def dualSendReceive[A <: Action, B <: Action, V](implicit w: Dual[A, B]): Dual[Send[V, A], Receive[V, B]] = witness
implicit def dualReceiveSend[A <: Action, B <: Action, V](implicit w: Dual[A, B]): Dual[Receive[V, A], Send[V, B]] = witness
implicit def dualInternalExternal[A1 <: Action, B1 <: Action, A2 <: Action, B2 <: Action, V](implicit a: Dual[A1, A2], b: Dual[B1, B2]): Dual[InternalChoice[A1, B1], ExternalChoice[A2, B2]] = witness
implicit def dualInternalExternalSwitched[A1 <: Action, B1 <: Action, A2 <: Action, B2 <: Action, V](implicit a: Dual[A1, B2], b: Dual[A1, B2]): Dual[InternalChoice[A1, B1], ExternalChoice[A2, B2]] = witness
implicit def dualExternalInternal[A1 <: Action, B1 <: Action, A2 <: Action, B2 <: Action, V](implicit a: Dual[A1, A2], b: Dual[B1, B2]): Dual[ExternalChoice[A1, B1], InternalChoice[A2, B2]] = witness
implicit def dualExternalInternalSwitched[A1 <: Action, B1 <: Action, A2 <: Action, B2 <: Action, V](implicit a: Dual[A1, B2], b: Dual[A1, B2]): Dual[ExternalChoice[A1, B1], InternalChoice[A2, B2]] = witness
def dual[A <: Action, B <: Action](a: A, b: B)(implicit w: Dual[A, B]) = witness
def dual[A <: Action, B <: Action](implicit w: Dual[A, B]) = witness
type a = Receive[String, Send[Int, End]]
type b = Send[String, Receive[Int, End]]
dual[a, b]
type c = String :?: Int :!: End
type d = String :!: Int :?: End
dual[c, d]
dual[a, d]
dual[b, c]
type e = String :?: (Int :!: End) :&: (Exception :!: End)
type f = String :!: (Int :?: End) :%: (Exception :?: End)
dual[e, f]
type g = Boolean :?: e :%: f
type h = Boolean :!: f :&: e
dual[g, h]
type g2 = Boolean :?: e :%: f
type h2 = Boolean :!: e :&: f
dual[g2, h2]
// Output
trait Writer[A <: Action] {
def parts: Seq[String]
}
implicit def writerForEnd: Writer[End] = new Writer[End] {
def parts = Seq("end")
}
implicit def writerForSend[V: ClassTag, A <: Action: Writer]: Writer[Send[V, A]] = new Writer[Send[V, A]] {
def parts = ("send " + classTag[V].toString) +: implicitly[Writer[A]].parts
}
implicit def writerForReceive[V: ClassTag, A <: Action: Writer]: Writer[Receive[V, A]] = new Writer[Receive[V, A]] {
def parts = ("receive " + classTag[V].toString) +: implicitly[Writer[A]].parts
}
implicit def writerForExternalChoice[V: ClassTag, A <: Action: Writer, B <: Action: Writer]: Writer[ExternalChoice[A, B]] = new Writer[ExternalChoice[A, B]] {
def parts = ("either" +: indent[A]) ++ indent[B]
}
implicit def writerForInternalChoice[V: ClassTag, A <: Action: Writer, B <: Action: Writer]: Writer[InternalChoice[A, B]] = new Writer[InternalChoice[A, B]] {
def parts = ("choose between" +: indent[A]) ++ indent[B]
}
private def indent[X <: Action: Writer] = {
val parts = implicitly[Writer[X]].parts
("- " + parts.head) +: parts.tail.map(" " + _)
}
implicit def outputSend[Value, A <: Action](a: Send[Value, A]) = "send"
def write[A <: Action](implicit writer: Writer[A]) = writer.parts.mkString("\n")
println("Protocol F:")
println(write[f])
println()
println("Protocol G:")
println(write[g])
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment