【发布时间】:2017-04-13 12:40:00
【问题描述】:
假设我有一堂课:
abstract class NumericCombine[A:Numeric,B:Numeric]{
type AB <: AnyVal
}
我想定义一个返回NumericCombine[A,B].AB 类型值的函数。例如:
def plus[A: Numeric,B:Numeric](x: A, y: B): NumericCombine[A,B].AB
但编译器不允许我在加号中引用.AB。
仅供参考,this 是这个问题的上下文。
我要提供:
implicit object IntFloat extends NumericCombine[Int,Float]{override type AB = Float}
implicit object FloatInt extends NumericCombine[Float,Int]{override type AB = Float}
和它的其他 44 个朋友 (7*6-2),这样我就可以定义我的 plus 如下:
def plus[A: Numeric,B:Numeric](x: A, y: B): NumericCombine[A,B].AB =
{
type AB = Numeric[NumericCombine[A,B].AB]
implicitly[AB].plus(x.asInstanceOf[AB],y.asInstanceOf[AB])
}
plus(1f,2)//=3f
plus(1,2f)//=3f
我知道 Scala 中的值转换允许我定义
def plus[T](a: T, b: T)(implicit ev:Numeric[T]): T = ev.plus(a,b)
并按照here 的建议实现上述行为,但由于我想将此函数用作更大函数的一部分(在此问题的上下文中提到的链接中进行了描述),我需要对函数进行参数化A 和 B。
更新:
我在这方面取得了一些不错的进展。
我的NumericCombine 现在看起来像这样:
abstract class NumericCombine[A: Numeric, B: Numeric] {
type AB <: AnyVal
def fromA(x: A): AB
def fromB(y: B): AB
val numeric: Numeric[AB]
def plus(x: A, y: B): AB = numeric.plus(fromA(x), fromB(y))
def minus(x: A, y: B): AB = numeric.minus(fromA(x), fromB(y))
def times(x: A, y: B): AB = numeric.times(fromA(x), fromB(y))
}
而我的 plus 函数看起来像:
def plus[A: Numeric, B: Numeric](x: A, y: B)(implicit ev:NumericCombine[A,B])
: ev.AB = ev.plus(x, y)
需要plus 的加权平均函数最终变得有点复杂:
def accumulateWeightedValue[A: Numeric,B: Numeric]
(accum: (A, NumericCombine[A, B]#AB), ValueWithWeight: (A, B))
(implicit combine: NumericCombine[A, B], timesNumeric: Numeric[NumericCombine[A, B]#AB])
:(A,NumericCombine[A, B]#AB)=
这是一个接受(A,AB),(A,B) 并返回(A,AB) 的函数。我在 weightedSum 内部使用它,它只是聚合在这个上面:
def weightedSum[A: Numeric,B: Numeric](weightedValues: GenTraversable[(A, B)])
(implicit numericCombine: NumericCombine[A, B], plusNumeric: Numeric[NumericCombine[A, B]#AB])
: (A, NumericCombine[A, B]#AB)
现在,这编译得很好。第二个隐式参数似乎确实有问题。即 Numeric[AB] 当我使用隐含值运行它时,比如 NumericCombine[Int,Float] 存在。它给了我:
找不到参数 plusNumeric 的隐含值: 数值[NumericCombine[Int,Float]#AB]
请注意,在 NumericCombine 中,我有一个 Numeric[AB] 应该可用于隐式查找。存储在本地,在[Int,Float]的情况下:
val lst: Seq[(Int, Float)] =List((1,3f),(1,4f))
implicit val num: Numeric[Float] = IntFloat.numeric //IntFloat extends NumericCombine[Int,Float]
weightedSum(lst)
在调用需要它的函数之前在局部变量中似乎没有任何影响。那么为什么会被隐式系统拾取呢。
【问题讨论】:
-
将
NumericCombine[A,B]#AB视为AB的所有NumericCombine[A,B]实例可能 存在的通用类型。所以accum的类型错误。 -
我明白了。那么有什么方法可以抽象出这些 AB 吗?允许其他函数使用这个泛型加号?
-
你说
accumulateWeightedValue在weightedSum内部使用。所以只要让它成为一个本地方法,你就可以使用numericCombine.AB。你不应该在A和B上需要plusNumeric或Numeric约束。 -
@AlexeyRomanov 你是说使用隐式作为函数的参数会阻止你的函数成为“一流的函数”,我应该只在本地使用它们吗?
-
不,我是说你应该在这种特定情况下这样做,因为
accum的类型应该取决于combine。
标签: scala type-alias