2010-12-14 71 views
2

一个观点我已经试过这行代码Scala编译器不能识别绑定

def **[A <% Numeric[A]](l:List[A],m:List[A])=l.zip(m).map({t=>t._1*t._2}) 

但是在编译时,当我看到在源的数字特征我得到这个错误

error: value * is not a member of type parameter A 
def **[A <% Numeric[A]](l:List[A],m:List[A])=l.zip(m).map({t=>t._1*t._2}) 

,我看到一个定义为*的操作。

我在做什么错?

回答

6

Numeric的实例本身不是数字,但它是提供操作来执行算术的对象。例如,Numeric[Int]类型的对象num可以添加两个整数像这样:num.plus(3, 5)该操作的结果是整7.

对于整数,这是非常简单。但是,对于所有基本数字类型,都有一个隐式Numeric的实例可用。如果你定义你自己的数字类型,你可以提供一个。

因此,您应该打开A的范围,并添加一个类型为Numeric[A]的隐式参数,并使用该参数进行计算。就像这样:

def **[A](l:List[A],m:List[A])(implicit num:Numeric[A])=l.zip(m).map({t=>num.times(t._1, t._2)}) 

当然,num.times(a,b)看起来比a*b那么优雅。在大多数情况下,人们可以忍受这一点。但是,您可以在Ops类型的对象,它支持运营商包的价值a,就像这样:

// given are: num:Numeric[A], a:A and b:A 
val a_ops = num.mkNumericOps(a) 
val product = a_ops * b 

由于该方法mkNumericOps声明implicit,你也可以导入并含蓄地使用它:

// given are: num:Numeric[A], a:A and b:A 
import num._ 
val product = a * b 
+1

我会在哪里把进口num._声明我的**功能的情况下? – user44242 2010-12-14 09:00:08

+1

您需要在等号后面打开一个块。我没有测试这个,但我想它应该看起来像这样:'def ** [A](l:List [A],m:List [A])(implicit num:Numeric [A])= {import num._; l.zip(m).map({t => t._1 * t._2})}' - 尽管如此,我会努力去尝试。我不确定隐式包装Ops对象的创建是否会影响性能,或者是否会被编译器优化。 – Madoc 2010-12-14 09:04:56

+0

我希望如果启用逃生分析,它应该进行优化,但没有保证。 – 2010-12-14 18:39:37

2

你也可以用context bound来解决这个问题。从this answer使用context方法,你可以写:

def **[A : Numeric](l:List[A],m:List[A]) = 
    l zip m map { t => context[A]().times(t._1, t._2) } 

def **[A : Numeric](l:List[A],m:List[A]) = { 
    val num = context[A]() 
    import num._ 
    l zip m map { t => t._1 * t._2 } 
} 
相关问题