如何在Scala中对通配符强制执行上下文绑定?

如何在Scala中对通配符强制执行上下文绑定?,scala,generics,wildcard,implicit,Scala,Generics,Wildcard,Implicit,我有一个隐式助手设置如下: trait Helper[T] { def help(entry: T): Unit } object Helpers { implicit object XHelper extends Helper[X] { override def help(entry: X): Unit = {println("x")} } implicit object YHelper extends Helper[Y] { override def hel

我有一个隐式助手设置如下:

trait Helper[T] {
  def help(entry: T): Unit
}

object Helpers {
  implicit object XHelper extends Helper[X] {
    override def help(entry: X): Unit = {println("x")}
  }
  implicit object YHelper extends Helper[Y] {
    override def help(entry: Y): Unit = {println("y")}
  }

  def help[T](entry: T)(implicit helper: Helper[T]): Unit = {
    helper.help(entry)
  }
}
我想建立一个元素集合,并对每个元素运行
help
。但是,下面给出了一个编译器错误,因为我们不能保证所有元素都有匹配的
Helper
s:

val data = Seq[_](new X(), new Y())
data.foreach(entry => Helpers.help(entry))

如果我们有一个泛型类型
T
,我们可以用
[T:Helper]
对它强制执行隐式约束,但这对
\uuuuz
不起作用。如何确保
数据
的每个元素都有一个匹配的
助手

Seq
这样的类型是不可能的,因为它只针对一个元素类型进行参数化,而该元素类型对其所有元素都是通用的

但是,您可以通过HLists和多态函数(Poly)实现这一点:

X类
Y类
特质帮助者[T]{
def帮助(条目:T):单位
}
对象帮助程序{
隐式对象XHelper扩展辅助对象[X]{
覆盖def帮助(条目:X):单位=println(“X”)
}
隐式对象YHelper扩展辅助对象[Y]{
覆盖def帮助(条目:Y):单位=打印项次(“Y”)
}
}
进口不成形_
对象辅助对象扩展Poly1{
隐式def tCase[T:Helper]:Case.Aux[T,Unit]=
at(隐式地[Helper[T]].help()
}
val hlist=新X::新Y::HNil
hlist.map(助手)
//输出:
x
Y

在Scala上下文绑定中,比如
类A[T:Typeclass]
只是
类A[T](隐式ev:Typeclass[T])
的语法糖。与
T:Super
不同,上下文绑定实际上不是类型签名的一部分,因此不能有像
valb:Box[T:Typeclass]
这样的签名

如果要对某些容器的元素运行typeclass操作,则必须将相关的typeclass实例与容器中的值打包在一起

可能的实现方式如下所示:

import language.higherKinds
import language.implicitConversions

// Class that packs values with typeclass instances
class WithTC[T, TC[_]](t: T)(implicit tc: TC[T]) {
  // Some helper methods to simplify executing typeclass operations
  // You may just make `t` and `tc` public, if you wish.
  def apply[U](op: (TC[T], T) => U) = op(tc, t)
  def apply[U](op: T => TC[T] => U) = op(t)(tc)
}
object WithTC {
  // Implicit conversion to automatically wrap values into `WithTC`
  implicit def apply[T, TC[_]](t: T)(implicit tc: TC[T]): WithTC[T, TC] =
    new WithTC(t)(tc)
}
然后,您可以使用存在类型的元素创建一个序列:

import Helpers._
val data: Seq[(T WithTC Helper) forSome { type T }] = Seq(new X(), new Y())
// The following lines produce equivalent results
data.foreach(_(_ help _))
data.foreach(_(t => implicit tc => Helpers.help(t)))
data.foreach(_(t => Helpers.help(t)(_)))
并对序列元素执行typeclass操作:

import Helpers._
val data: Seq[(T WithTC Helper) forSome { type T }] = Seq(new X(), new Y())
// The following lines produce equivalent results
data.foreach(_(_ help _))
data.foreach(_(t => implicit tc => Helpers.help(t)))
data.foreach(_(t => Helpers.help(t)(_)))

你能用一个新的特征来扩展类型
X
Y
,比如说
trait HasHelp
?不,不幸的是,代码不在我的控制范围之内。这让我感到惊讶,因为我可以做
Seq[\uu]这样的事情,比如
T:Helper
只是
的语法糖(隐式ev:Helper[T])
在一个方法中,所以我不确定它如何能够与值的参数化一起工作。