【问题标题】:Why does Numeric behave differently than Ordered?为什么 Numeric 的行为与 Ordered 不同?
【发布时间】:2011-01-26 10:29:11
【问题描述】:

Scala 有许多可以用作类型类的特征,例如 scala.math 包中的 OrderedNumeric

例如,我可以像这样使用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 trait 不包含* 之类的方法,而Ordered 包含&lt; 之类的方法?

我知道还有Ordering,你可以像Numeric一样使用它,另见this answer

def f[A : Ordering](a: A, b: A) = implicitly[Ordering[A]].compare(a, b)

【问题讨论】:

    标签: scala typeclass


    【解决方案1】:

    如果您从隐式 Numeric[T] 导入符号运算符,则可以使用它们

    def g[T : Numeric](a: T, b: T) = {
      val num = implicitly[Numeric[T]]
      import num._
      a * b
    }
    

    如果您只想使用单个运算符,这显然有点笨拙,但在非平凡的情况下,导入的开销并不是那么大。

    为什么没有显式导入操作符不可用?反对使隐式默认可见的通常考虑在这里适用,也许更重要的是因为这些运算符被广泛使用。

    【讨论】:

      【解决方案2】:

      Ordered 只是一些简单的 pimped 方法,它们返回 IntBoolean,因此不需要类型技巧。

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

      要恢复您的运算符,您可以在 lhs 操作数上使用 mkNumericOps(在 Numeric 中定义)。

      更新

      Miles 说的很对,mkNumericOps 是隐含的,所以只需导入 Numeric 的那个实例就可以恢复所有魔力...

      【讨论】:

        【解决方案3】:

        您可以通过执行以下操作将 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 了解更多信息。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-02-20
          • 1970-01-01
          • 2021-05-10
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多