Skip to content

Instantly share code, notes, and snippets.

@barambani
Forked from milessabin/typelevelcps.scala
Created August 27, 2018 12:45
Show Gist options
  • Save barambani/122e0f90adbe6d45e8f9dd566f5fecd8 to your computer and use it in GitHub Desktop.
Save barambani/122e0f90adbe6d45e8f9dd566f5fecd8 to your computer and use it in GitHub Desktop.
Using type level continuation passing style to rewrite a whitebox macro (which relies on fundep materialization) as a blackbox macro
import scala.language.higherKinds
// Whitebox ...
trait Schema[T, R] {
def conv(t: T): R
}
object Schema {
// Whitebox macro: R is computed from T
implicit def mkSchema[T, R]: Schema[T, R] = ??? // macro ...
}
trait UseComputed[A] {
def run(a: A): Int
}
object UseComputed {
implicit def mkUse[A]: UseComputed[A] = ???
}
object Test {
// R is bound by Schema[T, R] ... a ban on whitebox macros would prevent this
def foo[T, R](t: T)(implicit str: Schema[T, R], usr: UseComputed[R]): Int =
usr.run(str.conv(t))
}
// Blackbox via type level CPS conversion ...
trait SchemaCPS[T, Cont[_]] {
type R
def conv(t: T): R
val contR: Cont[R]
}
object SchemaCPS {
implicit def mkSchemaCPS[T, F[_]]: SchemaCPS[T, F] = ??? // macro ...
// Example expansion of macro
class SchemaUseComputed[T] extends SchemaCPS[T, UseComputed] {
type R = Option[T] // arbitrary computed type
def conv(t: T): R = Some(t)
val contR = implicitly[UseComputed[R]] // continuation materialized in macro expansion
}
}
object TestCPS {
// Note that R is abstract and never escapes ... this is blackbox
def foo[T](t: T)(implicit suc: SchemaCPS[T, UseComputed]): Int = {
import suc._
contR.run(conv(t))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment