Skip to content

Instantly share code, notes, and snippets.

@Kraks
Created May 10, 2019 00:45
Show Gist options
  • Save Kraks/dea276c7f3e4631e9944d8b36565877e to your computer and use it in GitHub Desktop.
Save Kraks/dea276c7f3e4631e9944d8b36565877e to your computer and use it in GitHub Desktop.
Some types of Futamura projections.
trait Futamura1 {
// Roughly follow the idea from http://blog.sigfpe.com/2009/05/three-projections-of-doctor-futamura.html
type P[_] // program representation type
type M[_] // machine type
/* To run a machine: */
def run[A](ma: M[A]): A
/* The specializer: a machine that
takes a program representation of A => B,
specializes it wrt a value of A, and
yields a machine of M[B].
*/
def specializer[A, B]: M[P[A => B] => A => M[B]]
/* The program representation of specializer */
def specializerProgram[A, B]: P[P[A => B] => A => M[B]]
/* The interpreter: a machine that
takes a program representation of A => B and a value of A,
executes the program, and
yields a value of B.
*/
def interpreter[A, B]: M[P[A => B] => A => B]
def abstractInterpreter[A, B, α[_]]: M[P[A => B] => α[A] => α[B]]
/* The program representation of interpreter */
def interpreterProgram[A, B]: P[P[A => B] => A => B]
/* Yields executables */
def firstProjection[A, B](prog: P[A => B]): M[A => B] =
run(specializer[P[A => B], A => B])(interpreterProgram[A, B])(prog)
def specializedSpecializerProgram[A, B]: P[A => B] => M[A => M[B]] =
run(specializer[P[A => B], A => M[B]])(specializerProgram[A, B])
/* A self-hosting specializer, ie a compiler */
def secondProjection[A, B]: M[P[A => B] => M[A => B]] =
specializedSpecializerProgram(interpreterProgram[A, B])
/* A compiler-compiler, converting any interpreter to an equivalent compiler */
def thirdProjection[A, B]: M[P[A => B] => M[A => M[B]]] =
specializedSpecializerProgram(specializerProgram[A, B])
/* The fourth projection is a quine */
def quine[A, B]: M[P[A => B] => M[A => M[B]]] =
run(thirdProjection[P[A => B], A => M[B]])(specializerProgram[A, B])
}
trait Futamura2 {
// From Matt Brown and Jens Palsberg's POPL '18 paper
type Rep[_]
def unRep[A](x: Rep[A]): A
def toRep[A](x: A): Rep[A]
def mix[A, B]: Rep[A => B] => Rep[A] => Rep[B]
def interp[A, B]: Rep[A => B] => A => B
def compiler[A, B]: Rep[A] => Rep[B]
def first[A, B](prog: Rep[Rep[A => B]]): Rep[A => B] = mix(toRep(interp[A, B]))(prog)
def mixmix[A, B]: Rep[Rep[A => B]] => Rep[Rep[A] => Rep[B]] = mix(toRep(mix))
def second[A, B]: Rep[Rep[Rep[A => B]] => Rep[A => B]] = mixmix(toRep(toRep(interp[A, B])))
def third[A, B]: Rep[Rep[Rep[A => B]] => Rep[Rep[A] => Rep[B]]] = mixmix(toRep(toRep(mix[A, B])))
def fourth[A, B]: Rep[Rep[Rep[A => B]] => Rep[Rep[A] => Rep[B]]] =
unRep(third[Rep[A => B], Rep[A] => Rep[B]])(toRep(toRep(mix[A, B])))
}
trait Futamura3 {
// From Jones, Gomard, and Sestoft's partial evaluation book
// The difference is the type of mix: the second argument is A (instead of Rep[A] from Brown & Palsberg)
type Rep[_]
def toRep[A](x: A): Rep[A]
def unRep[A](x: Rep[A]): A
def mix[A, B]: Rep[A => B] => A => Rep[B]
def interp[A, B]: Rep[A => B] => A => B
def first[A, B](prog: Rep[A => B]): Rep[A => B] =
mix[Rep[A => B], A => B](toRep(interp[A, B]))(prog)
def mixmix[A, B]: Rep[A => B] => Rep[A => Rep[B]] = mix(toRep(mix[A, B]))
def second[A, B]: Rep[Rep[A => B] => Rep[A => B]] = mixmix(toRep(interp[A, B]))
def third[A, B]: Rep[Rep[A => B] => Rep[A => Rep[B]]] = mixmix(toRep(mix[A, B]))
def fourth[A, B]: Rep[Rep[A => B] => Rep[A => Rep[B]]] = unRep(third[Rep[A => B], A => Rep[B]])(toRep(mix[A, B]))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment