Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Context bounds for generic polymorphic data in collection

I have the simplified situation:

abstract sealed trait Top
class A[T] extends Top
class B[T] extends Top

class Typeclass[T]
implicit def a[T] = new Typeclass[A[T]]
implicit def b[T] = new Typeclass[B[T]]

Now I have a Map[String, Top] and want to use an operation on all values in the map that require the presence of an instance of Typeclass to be available in the context. This will not compile as the concrete types of the values in the map are not visible from its type and I can therefore not set a context bound for them.

Is there a way to tell the compiler that in fact there will always be an instance available? In this example this is given as there are implicit functions to generate those instances for every concrete subtype of Top.

Or is the only solution to use a HList and recurse over its type requiring all the instances to be in context?

like image 884
mgttlinger Avatar asked Sep 14 '26 22:09

mgttlinger


1 Answers

I recommend using some variation on this adaptation of Oleg's Existentials as universals in this sort of situation ... pack the the type class instance along with the value it's the instance for,

abstract sealed trait Top
class A[T] extends Top
class B[T] extends Top

class Typeclass[T]
implicit def a[T] = new Typeclass[A[T]]
implicit def b[T] = new Typeclass[B[T]]

trait Pack {
  type T <: Top
  val top: T
  implicit val tc: Typeclass[T]
}

object Pack {
  def apply[T0 <: Top](t0: T0)(implicit tc0: Typeclass[T0]): Pack =
    new Pack { type T = T0 ; val top = t0 ; val tc = tc0 }
}

val m = Map("a" -> Pack(new A[Int]), "b" -> Pack(new B[Double]))

def foo[T: Typeclass](t: T): Unit = ()

def bar(m: Map[String, Pack], k: String): Unit =
  m.get(k).map { pack =>
    import pack._ // imports T, top and implicit tc
    foo(top)      // instance available for call of foo
  }

bar(m, "a")
like image 183
Miles Sabin Avatar answered Sep 16 '26 16:09

Miles Sabin



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!