Last active
September 16, 2019 13:44
-
-
Save milessabin/cadd73b7756fe4097ca0 to your computer and use it in GitHub Desktop.
A new approach to encoding dependently-typed chained implicits, using singleton types ...
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
object Demo { | |
// A couple of type classes with type members ... | |
trait Foo[T] { | |
type A | |
} | |
object Foo { | |
implicit val fooIS = new Foo[Int] { type A = String } | |
} | |
trait Bar[T] { | |
type B | |
val value: B | |
} | |
object Bar { | |
implicit val barSB = new Bar[String] { | |
type B = Boolean | |
val value = true | |
} | |
} | |
// What we want to write ... | |
// | |
// def run[T](t: T)(implicit foo: Foo[T], bar: Bar[foo.A]): bar.B = bar.value | |
// | |
// or maybe ... | |
// | |
// def run[T](t: T)(implicit foo: Foo[T])(implicit bar: Bar[foo.A]): bar.B = bar.value | |
// | |
// but can't ... in the first case the compiler complains about a dependent type (foo.A) | |
// appearing in the same parameter block as its prefix (foo); in the second the compiler | |
// chokes on the multiple implicit parameter blocks. | |
// But we can encode the above with the help of singleton types ... | |
// SingletonOf[T, U] represents an implicit value of type T narrowed to its | |
// singleton type U. | |
case class SingletonOf[T, U](value: U) | |
object SingletonOf { | |
implicit def mkSingletonOf[T <: AnyRef](implicit t: T): SingletonOf[T, t.type] = SingletonOf(t) | |
} | |
// The implicit resolution of SingletonOf[Foo[T], fooT] will result in the type | |
// fooT being inferred as the singleton type of the in-scope Foo[T] value. | |
// We then rely on the equivalence between, | |
// | |
// foo.A | |
// | |
// and, | |
// | |
// foo.type#A | |
// | |
// to rewrite the problematic dependently chained parameter block to a form | |
// that scalac is happy to digest ... | |
def run[T, fooT <: { type A }](t: T) | |
(implicit sFoo: SingletonOf[Foo[T], fooT], bar: Bar[fooT#A]): bar.B = bar.value | |
val value = run(23) | |
assert(value: Boolean) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I guess we need scala/docs.scala-lang#520