Scala 如何减少泛型方法中不需要的类型参数?
我想用一些灵活的方法实现一些通用的数学函数。 e、 g.一个名为Scala 如何减少泛型方法中不需要的类型参数?,scala,generics,Scala,Generics,我想用一些灵活的方法实现一些通用的数学函数。 e、 g.一个名为meandot的函数,声明为 object Calc { def meandot[..](xs: Array[Left], ys: Array[Right])(implicit ..): Result } 其中meandot(xs,ys)=和(x*y表示x,y在zip中(xs,ys))/length 当我在没有特殊类型参数的情况下调用meandot时,它应该返回一个默认类型的值。e、 g scala> Calc.mean
meandot
的函数,声明为
object Calc {
def meandot[..](xs: Array[Left], ys: Array[Right])(implicit ..): Result
}
其中meandot(xs,ys)=和(x*y表示x,y在zip中(xs,ys))/length
当我在没有特殊类型参数的情况下调用meandot
时,它应该返回一个默认类型的值。e、 g
scala> Calc.meandot(Array(1, 2), Array(1, 1))
res0: Int = 1
如果使用专用类型参数调用meandot
,它可以返回一个正确的值
scala> Calc.meandot[Int, Int, Double](Array(1, 2), Array(1, 1))
res1: Double = 1.5
但是,上面的前两个类型参数是冗余的。我需要专门化的唯一类型是返回类型。我想把它简化为
scala> Calc.meandot2(Array(1, 2), Array(1, 1))
res2: Int = 1
scala> Calc.meandot2[Double](Array(1, 2), Array(1, 1))
res3: Double = 1.5
我发现了一种实现它的方法,如下代码所示,它使用代理类MeanDotImp
但它似乎不那么优雅。因此,我想知道是否有更好的解决方案来减少泛型方法中不需要的类型参数?
trait Times[L, R, N] {
def times(x: L, y: R): N
}
trait Num[N] {
def zero: N = fromInt(0)
def one: N = fromInt(1)
def fromInt(i: Int): N
def plus(x: N, y: N): N
def div(x: N, y: N): N
}
abstract class LowTimesImplicits {
implicit val IID: Times[Int, Int, Double] = new Times[Int, Int, Double] {
def times(x: Int, y: Int): Double = x * y
}
}
object Times extends LowTimesImplicits {
implicit val III: Times[Int, Int, Int] = new Times[Int, Int, Int] {
def times(x: Int, y: Int): Int = x * y
}
}
object Num {
implicit val INT: Num[Int] = new Num[Int] {
def fromInt(i: Int): Int = i
def plus(x: Int, y: Int): Int = x + y
def div(x: Int, y: Int): Int = x / y
}
implicit val DOU: Num[Double] = new Num[Double] {
def fromInt(i: Int): Double = i
def plus(x: Double, y: Double): Double = x + y
def div(x: Double, y: Double): Double = x / y
}
}
object Calc {
def meandot[L, R, N](xs: Array[L], ys: Array[R])
(implicit t: Times[L, R, N], n: Num[N]): N = {
val total = (xs, ys).zipped.foldLeft(n.zero){
case(r, (x, y)) => n.plus(r, t.times(x, y))
}
n.div(total, n.fromInt(xs.length))
}
implicit class MeanDotImp[L, R](val marker: Calc.type) {
def meandot2[N](xs: Array[L], ys: Array[R])
(implicit t: Times[L, R, N], n: Num[N]): N = {
val total = (xs, ys).zipped.foldLeft(n.zero){
case(r, (x, y)) => n.plus(r, t.times(x, y))
}
n.div(total, n.fromInt(xs.length))
}
}
}
另一种解决方案与您的类似,但更为简单:它首先修复您希望能够设置的类型参数,然后推断其他两个。为了实现这一点,我们可以使用
apply
方法声明一个类:
class meandot[N] {
def apply[L, R](xs: Array[L], ys: Array[R])
(implicit t: Times[L, R, N], n: Num[N]): N = ??? // your implementation
}
现在,为了避免编写new meandot
,我们可以定义一个只实例化此类的方法:
object Calc {
def meandot[N]: meandot[N] = new meandot[N]
}
这种方法的优雅是有争议的,但它非常简单,不涉及隐含的。下面是一个用法演示:
scala> Calc.meandot(Array(1,2,3), Array(4,5,6))
res0: Int = 10
scala> Calc.meandot[Double](Array(1,2,3), Array(4,5,6))
res1: Double = 10.666666666666666
因此,您希望能够调用
meandot[Double](…)
,但仍然可以打开调用meandot[Int,Short,Float](…)
(或类似的选项)。是这样的吗?@ JWVH,即使我只能调用<代码> Meunt[Dou](数组[L],数组[r])< />代码> <代码> L,r>代码>可以是<代码> int、浮点、双< /代码>等。如果您正在做大量的数学运算,请考虑我更喜欢您的解决方案。