为什么 scala 编译器说类型参数不符合边界?
why scala compiler says type arguments does not conform to bounds?
我用子类 Complex 和 IntCombiner 创建了 Combiner trait,我的 objective 是让 Matrix 与 Complex 和 Int 一起工作。但由于某种原因它没有编译说
[com.implicits.TestImplicits1.IntCombiner] do not conform to class Matrix's type parameter bounds [T <: com.implicits.TestImplicits1.Combiner[T]]
val m1 = new Matrix[IntCombiner](3, 3)((1 to 9).sliding(3).map {
但据我了解,IntContainer 是 Combiner 的子类,它应该可以工作。为什么会出现这样的错误,请解释一下?
object TestImplicits1 {
trait Combiner[T] {
def +(b: T): T
def *(b: T): T
}
class Complex(r: Double, i: Double) extends Combiner[Complex] {
val real = r
val im = i
override def +(b: Complex): Complex = {
new Complex(real + b.real, im + b.im)
}
override def *(b: Complex): Complex = {
new Complex((real * b.real) - (im * b.im), real * b.im + b.real * im)
}
}
class IntCombiner(a: Int) extends Combiner[Int] {
val v = a
override def *(b: Int): Int = v * b
override def +(b: Int): Int = v + b
}
class Matrix[T <: Combiner[T]](x1: Int, y1: Int)(ma: Seq[Seq[T]]) {
self =>
val x: Int = x1
val y: Int = y1
def dot(v1: Seq[T], v2: Seq[T]): T = {
v1.zip(v2).map { t: (T, T) => {
t._1 * t._2
}
}.reduce(_ + _)
}
}
object MatrixInt extends App {
def apply[T <: Combiner[T]](x1: Int, y1: Int)(s: Seq[Seq[T]]) = {
new Matrix[T](x1, y1)(s)
}
val m1 = new Matrix[IntCombiner](3, 3)((1 to 9).sliding(3).map {
x => x map { y => new IntCombiner(y) }
}.toSeq)
}
}
F-bounded 多态性不能添加到现有的 Int
class,因为 Int
就是它的本来面目,它对你的 Combiner
一无所知特征,所以它不能扩展 Combiner[Int]
。您可以将每个 Int
包装成 IntWrapper <: Combiner[IntWrapper]
之类的东西,但这会浪费相当多的内存,并且围绕 F-bounded 多态性的库设计往往很棘手。
这是一个基于临时多态性的建议,类型classes 改为:
object TestImplicits1 {
trait Combiner[T] {
def +(a: T, b: T): T
def *(a: T, b: T): T
}
object syntax {
object combiner {
implicit class CombinerOps[A](a: A) {
def +(b: A)(implicit comb: Combiner[A]) = comb.+(a, b)
def *(b: A)(implicit comb: Combiner[A]) = comb.*(a, b)
}
}
}
case class Complex(re: Double, im: Double)
implicit val complexCombiner: Combiner[Complex] = new Combiner[Complex] {
override def +(a: Complex, b: Complex): Complex = {
Complex(a.re + b.re, a.im + b.im)
}
override def *(a: Complex, b: Complex): Complex = {
Complex((a.re * b.re) - (a.im * b.im), a.re * b.im + b.re * a.im)
}
}
implicit val intCombiner: Combiner[Int] = new Combiner[Int] {
override def *(a: Int, b: Int): Int = a * b
override def +(a: Int, b: Int): Int = a + b
}
class Matrix[T: Combiner](entries: Vector[Vector[T]]) {
def frobeniusNormSq: T = {
import syntax.combiner._
entries.map(_.map(x => x * x).reduce(_ + _)).reduce(_ + _)
}
}
}
我不知道你在 dot
那里尝试了什么,你的 x1
、x2
和 ma
似乎完全没有用过,所以我添加了一个简单的取而代之的是 Frobenius 范数平方示例,只是为了展示 typeclasses 和运算符的语法糖是如何协同工作的。请不要期望它有任何与 "high performance" 相似的东西——JVM 传统上从不关心矩形数组和数字运算(至少在单个计算节点上不关心;Spark & Co 是另一回事)。至少您的代码不会自动转换为优化的 CUDA 代码,这是肯定的。
我用子类 Complex 和 IntCombiner 创建了 Combiner trait,我的 objective 是让 Matrix 与 Complex 和 Int 一起工作。但由于某种原因它没有编译说
[com.implicits.TestImplicits1.IntCombiner] do not conform to class Matrix's type parameter bounds [T <: com.implicits.TestImplicits1.Combiner[T]]
val m1 = new Matrix[IntCombiner](3, 3)((1 to 9).sliding(3).map {
但据我了解,IntContainer 是 Combiner 的子类,它应该可以工作。为什么会出现这样的错误,请解释一下?
object TestImplicits1 {
trait Combiner[T] {
def +(b: T): T
def *(b: T): T
}
class Complex(r: Double, i: Double) extends Combiner[Complex] {
val real = r
val im = i
override def +(b: Complex): Complex = {
new Complex(real + b.real, im + b.im)
}
override def *(b: Complex): Complex = {
new Complex((real * b.real) - (im * b.im), real * b.im + b.real * im)
}
}
class IntCombiner(a: Int) extends Combiner[Int] {
val v = a
override def *(b: Int): Int = v * b
override def +(b: Int): Int = v + b
}
class Matrix[T <: Combiner[T]](x1: Int, y1: Int)(ma: Seq[Seq[T]]) {
self =>
val x: Int = x1
val y: Int = y1
def dot(v1: Seq[T], v2: Seq[T]): T = {
v1.zip(v2).map { t: (T, T) => {
t._1 * t._2
}
}.reduce(_ + _)
}
}
object MatrixInt extends App {
def apply[T <: Combiner[T]](x1: Int, y1: Int)(s: Seq[Seq[T]]) = {
new Matrix[T](x1, y1)(s)
}
val m1 = new Matrix[IntCombiner](3, 3)((1 to 9).sliding(3).map {
x => x map { y => new IntCombiner(y) }
}.toSeq)
}
}
F-bounded 多态性不能添加到现有的 Int
class,因为 Int
就是它的本来面目,它对你的 Combiner
一无所知特征,所以它不能扩展 Combiner[Int]
。您可以将每个 Int
包装成 IntWrapper <: Combiner[IntWrapper]
之类的东西,但这会浪费相当多的内存,并且围绕 F-bounded 多态性的库设计往往很棘手。
这是一个基于临时多态性的建议,类型classes 改为:
object TestImplicits1 {
trait Combiner[T] {
def +(a: T, b: T): T
def *(a: T, b: T): T
}
object syntax {
object combiner {
implicit class CombinerOps[A](a: A) {
def +(b: A)(implicit comb: Combiner[A]) = comb.+(a, b)
def *(b: A)(implicit comb: Combiner[A]) = comb.*(a, b)
}
}
}
case class Complex(re: Double, im: Double)
implicit val complexCombiner: Combiner[Complex] = new Combiner[Complex] {
override def +(a: Complex, b: Complex): Complex = {
Complex(a.re + b.re, a.im + b.im)
}
override def *(a: Complex, b: Complex): Complex = {
Complex((a.re * b.re) - (a.im * b.im), a.re * b.im + b.re * a.im)
}
}
implicit val intCombiner: Combiner[Int] = new Combiner[Int] {
override def *(a: Int, b: Int): Int = a * b
override def +(a: Int, b: Int): Int = a + b
}
class Matrix[T: Combiner](entries: Vector[Vector[T]]) {
def frobeniusNormSq: T = {
import syntax.combiner._
entries.map(_.map(x => x * x).reduce(_ + _)).reduce(_ + _)
}
}
}
我不知道你在 dot
那里尝试了什么,你的 x1
、x2
和 ma
似乎完全没有用过,所以我添加了一个简单的取而代之的是 Frobenius 范数平方示例,只是为了展示 typeclasses 和运算符的语法糖是如何协同工作的。请不要期望它有任何与 "high performance" 相似的东西——JVM 传统上从不关心矩形数组和数字运算(至少在单个计算节点上不关心;Spark & Co 是另一回事)。至少您的代码不会自动转换为优化的 CUDA 代码,这是肯定的。