Scala 集合中泛型多态数据的上下文边界

Scala 集合中泛型多态数据的上下文边界,scala,generics,polymorphism,implicit,Scala,Generics,Polymorphism,Implicit,我有一个简化的情况: 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]] 现在我有了一个映射[String,Top],并希望对映射中所有需要在上下文中提供Typeclass实例的值使用一个操作。这不会编译,

我有一个简化的情况:

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]]
现在我有了一个
映射[String,Top]
,并希望对映射中所有需要在上下文中提供
Typeclass
实例的值使用一个操作。这不会编译,因为映射中的值的具体类型在其类型中不可见,因此我无法为它们设置上下文绑定

有没有办法告诉编译器,事实上总是有一个实例可用?在本例中,这是因为有隐式函数为
Top
的每个具体子类型生成这些实例


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

如注释中所述,在
Top
上定义typeclass会更方便,并且可以通过模式匹配来完成

假设typeclass的部分定义是

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)
}
如果调用泛型方法既合法又安全,例如使用存在(
a
匹配
a[\u]


然而,考虑到存在式的简化信息,可能很难让编译器相信传递给
f
的参数或得到的结果是正确的。如果是这样的话,请张贴您需要的签名。

我建议在这种情况下使用Oleg的这种改编版本的一些变体。。。将类型类实例与其实例对应的值打包

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")
abstract
A类[T]扩展到顶部
B类[T]扩展到顶部
类别类别类别[T]
隐式定义a[T]=新类型类[a[T]]
隐式定义b[T]=新类型类[b[T]]
特征包{
T型包装(新B型[双])
def foo[T:Typeclass](T:T):单位=()
def条(m:Map[String,Pack],k:String):单位=
m、 get(k).map{pack=>
导入包。\导入T、顶部和隐式tc
foo(top)//实例可用于调用foo
}
酒吧(m,“a”)

是否有理由不在顶部定义typeclass实例(或在补充中?)无论如何,编译器不会满足于知道一个实例将可用。它会在编译时想知道哪个实例。@DidierDupont
Typeclass
实例的实现取决于类型
T
以及
A
B
的成员(在我的实际用例中).我不知道如何通过模式匹配在
Top
@DidierDupont上实现这一点,我可以区分
A
B
,但据我所知,我无法从中获得类型
t
(不匹配所有可能的类型
t
).好的,转到答案以获得更多空间。如果
fOnA
fOnB
有(不同的)怎么办类型
T
上的上下文边界?在存在状态下调用该方法是合法和安全的,但强制将结果返回到预期的结果类型
fOnT
…您需要在case子句体中使用不安全的强制转换来编译它。@milessbin:一般来说是正确的,但在很多情况下,例如返回类型不是参数的,或者是协变的。参数也可能是一个问题。显然,每个a[T]和B[T]上的幺半群不会使其成为顶部的幺半群,而强制转换也不会使其成为顶部的幺半群。当foo签名不那么琐碎时,它会比模式匹配更好吗?我的直觉是,它可能会成为顶部的幺半群(当然,情况不会更糟),但我无法指出哪种情况会更糟。模式匹配总是容易受到擦除问题的影响。这种方法不是因为在已知静态类型值的点上选择实例。