为什么Numeric的行为与Ordered不同?

时间:2011-01-26 10:29:12

标签: scala typeclass

Scala有许多可用作类型的特征,例如Ordered包中的Numericscala.math

例如,我可以使用Ordered编写一个通用方法,如下所示:

def f[T <% Ordered[T]](a: T, b: T) = if (a < b) a else b

我想与Numeric做类似的事情,但这不起作用:

def g[T <% Numeric[T]](a: T, b: T) = a * b

为什么OrderedNumeric之间存在明显的差异?

我知道还有其他方法可以做到这一点,以下方法可行(使用上下文绑定):

def g[T : Numeric](a: T, b: T) = implicitly[Numeric[T]].times(a, b)

但这看起来比仅仅使用*乘以两个数字更复杂。为什么Numeric特征不包含*等方法,而Ordered包含<等方法?

我知道还有Ordering,您可以像Numeric一样使用def f[A : Ordering](a: A, b: A) = implicitly[Ordering[A]].compare(a, b) ,另请参阅this answer

{{1}}

3 个答案:

答案 0 :(得分:12)

如果从隐式Numeric [T]

导入符号运算符,则它们可用
def g[T : Numeric](a: T, b: T) = {
  val num = implicitly[Numeric[T]]
  import num._
  a * b
}

如果你想只使用一个操作符,这显然有点笨拙,但在非平凡的情况下,导入的开销并不是那么好。

如果没有显式导入,为什么运营商不可用?默认情况下,默认情况下使隐含可见的常见考虑因素在这里适用,可能更常见,因为这些运算符被广泛使用。

答案 1 :(得分:5)

Ordered只是一些返回IntBoolean的简单拉皮条方法,因此不需要任何类型技巧。

另一方面,

Numeric具有根据所使用的确切子类返回不同类型的方法。因此,Ordered只是标记特征,Numeric是一个功能齐全的类型。

要让您的操作员回来,您可以在lhs操作数上使用mkNumericOps(在Numeric中定义)。

<强>更新

Miles非常正确,mkNumericOps是隐含的,所以只需导入Numeric实例就可以让你恢复所有魔法......

答案 2 :(得分:5)

你可以通过这样做来减少Miles的解决方案只使用1个额外的行:

添加从A : NumericNumeric[A]#Ops

的隐式转换
object Ops {
  implicit def numeric[A : Numeric](a: A) = implicitly[Numeric[A]].mkNumericOps(a)
}

然后将其纳入您方法的范围

def g[T : Numeric](a: T, b: T) = {
  import Ops.numeric
  a * b
}

有关详细信息,请参阅Scala ticket 3538