集合中通用多态数据的上下文边界

Context bounds for generic polymorphic data in collection

我有简化的情况:

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]]

现在我有一个 Map[String, Top] 并且想对映射中的所有值使用操作,这些值需要存在 Typeclass 的实例才能在上下文中可用。这不会编译,因为地图中值的具体类型从其类型中不可见,因此我无法为它们设置上下文绑定。

有没有办法告诉编译器事实上总会有一个实例可用?在这个例子中,这是因为有隐式函数可以为 Top.

的每个具体子类型生成这些实例

或者使用 HList 并递归其类型要求所有实例都在上下文中的唯一解决方案?

正如评论中所讨论的那样,在 Top 上定义类型类会更方便,并且可以通过模式匹配来完成。

假设类型类定义的一部分是

def f[T](t: T): FResult[T], 

你有相应的实现

def fOnA[T](t: A[T]): FResult[A[T]] = ...
def fOnB[T](t: B[T]): FResult[B[T]] = ...

然后你可以定义

def fOnT(t: Top) : FResult[Top] = t match {
  case a: A[_] => fOnA(a) 
    // provided an FResult[A[T]] is an FResult[Top], 
    // or some conversion is possible
  case b: B[_] => fOnB(b)
}

If 调用泛型方法既合法又安全,例如 fOnA[T] 具有存在性(a 匹配 A[_]

但是,考虑到存在信息的减少,可能很难让编译器相信您传递给 f 的参数或您获得的结果是正确的。如果有,请post您需要的签名。

我建议在这种情况下对 Oleg 的 Existentials as universals 的这种改编使用一些变体...打包类型 class 实例及其实例的值,

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")