Почему Numeric ведет себя не так, как заказано? - PullRequest
10 голосов
/ 26 января 2011

Scala имеет ряд характеристик, которые вы можете использовать в качестве классов типов, например Ordered и Numeric в пакете scala.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

Почему существует явное расхождение междуOrdered и Numeric?

Я знаю, что есть другие способы сделать это, сработает следующее (использует контекстную границу):

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)

Ответы [ 3 ]

12 голосов
/ 26 января 2011

Символические операторы доступны, если вы импортируете их из неявного числа [T]

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

Это явно немного громоздко, если вы хотите использовать только один оператор, но в нетривиальных случаях накладные расходы на импорт не так уж велики.

Почему операторы недоступны без явного импорта? Здесь применимы обычные соображения против отображения последствий по умолчанию, возможно, в большей степени потому, что эти операторы широко используются.

5 голосов
/ 26 января 2011

Вы можете уменьшить решение Miles, чтобы использовать только 1 дополнительную строку, выполнив следующее:

Добавить неявное преобразование из A : Numeric в Numeric[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 3538 .

5 голосов
/ 26 января 2011

Ordered - это всего лишь несколько простых pimped-методов, которые возвращают либо Int, либо Boolean, поэтому нет необходимости в обмане типов

Numeric, с другой стороны, имеет методы, которые возвращают различные типы в зависимости от используемого подкласса. Таким образом, хотя Ordered - это чуть больше, чем признак маркера, Numeric - это полнофункциональный класс типов.

Чтобы вернуть своих операторов, вы можете использовать mkNumericOps (определенный в Numeric) с операндом lhs.

UPDATE

Майлз совершенно прав, mkNumericOps неявный, поэтому простой импорт этого экземпляра Numeric вернет вам всю магию ...

...