Create a gist now

Instantly share code, notes, and snippets.

A new approach to encoding dependently-typed chained implicits, using singleton types ...
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)
}
@ikhoon
ikhoon commented Jun 18, 2016

👍

@Atry
Atry commented Mar 14, 2017 edited

This gist does not work on Dotty because Dotty does not support fooT#A.
https://scastie.scala-lang.org/Atry/MVT3eSKASre9efquImTopA

@Atry
Atry commented Mar 14, 2017

I guess we need scala/scala.github.com#520

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment