Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
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 commented Jun 18, 2016


Atry commented Mar 14, 2017

This gist does not work on Dotty because Dotty does not support fooT#A.

Atry commented Mar 14, 2017

I guess we need scala/

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