Почему неявное преобразование не рассматривается в этом случае с универсальными параметрами?

Рассмотрим следующий код, полученный из проекта metascala:

object Units {
  case class Quantity[M <: MInt, T: Numeric](value: T) {
    type This = Quantity[M, T]

    def *[M2 <: MInt](m: Quantity[M2, T]) = 
      Quantity[M + M2, T](numeric[T].times(value, m.value))
    def /[M2 <: MInt](m: Quantity[M2, T]) = 
      Quantity[M - M2, T](numeric[T].div(value, m.value))
    def apply(v: T) = Quantity[M, T](numeric[T].times(v, value))
  }

  implicit def measure[T: Numeric](v: T) = Quantity[_0, T](v)

  implicit def numericToQuantity[T: Numeric](v: T) = 
    new QuantityConstructor[T](v)

  class QuantityConstructor[T: Numeric](v: T) {
    def m = Quantity[_1, T](v)
  }
}

(MInt — это в основном реализация чисел Пеано, где _0, _1 — это конкретные «значения» из metascala. Скажите, если вам нужен дополнительный код, я просто не хотел вставлять все сюда.)

Я хочу поддерживать код, в котором некоторое существующее количество можно умножить на простое число, например. грамм.

import Units._

val length1 = 5  * (5 m) //doesn't work <-----
val length2 = (5 m) * 5  // works

Почему неявный метод measure не рассматривается в первой строке кода, как я предполагал?

Вместо этого я получаю это сообщение об ошибке:

overloaded method value * with alternatives:
   (x: Double)Double <and>
   (x: Float)Float <and>
   (x: Long)Long <and>
   (x: Int)Int <and>
   (x: Char)Int <and>
   (x: Short)Int <and>
   (x: Byte)Int  cannot be applied to 
(scalax.units.Units3.Quantity[scalax.units.Integers._1,Int])

Я использую Scala 2.10-trunk.

На самом деле это продолжение Как работает ли '1 * BigInt(1)' и как я могу сделать то же самое?.


person soc    schedule 04.10.2011    source источник
comment
Где вы определяете implicit def measure? Какая версия Скала? Чтобы это работало, определение measure должно быть либо в локальной области, либо в неявной области, и в соответствии с ответ ретронима на ваш предыдущий вопрос, правила для неявной области скоро станут более мощными. Для получения более подробной информации об имплицитах я настоятельно рекомендую руководство Дэниела Собрала.   -  person Kipton Barros    schedule 04.10.2011
comment
Я уточнил код. Первый блок кода находится в одном объекте, который импортируется во второй блок кода.   -  person soc    schedule 04.10.2011


Ответы (1)


Чтобы начать, вот отдельный пример, который дает ту же проблему,

object Units {
  case class Quantity[T: Numeric](value: T) {
    def *[M](m: Quantity[T]) =           // type M can't be inferred below
      Quantity[T](implicitly[Numeric[T]].times(value, m.value))
  }
  implicit def measure[T: Numeric](v: T) = Quantity[T](v)

  val length0 = measure(5) * Quantity(5) // works
  val length1 = 5  * Quantity(5)         // doesn't work
}

По какой-то причине преобразование measure не найдено из-за параметра типа M в методе *. Если параметр типа удален из *, компилируется нормально. Может быть, кто-то еще может объяснить, почему?

Изменить. Это похоже на ограничение компилятора Scala, поскольку переименование * во что-то вроде *** решает проблему. Возможно, существование Int.* (без параметра типа) препятствует неявному преобразованию для использования Quantity.*[M] (с параметром типа). Это напоминает мне о требовании, чтобы переопределенные методы имели те же точные параметры типа.

person Kipton Barros    schedule 04.10.2011
comment
Да, я был бы признателен! - person soc; 04.10.2011
comment
Странно, что в моем примере указан параметр типа Quantity[_0, T], и он все еще не работает. Я также пытался добавить явный тип возврата к implicit, но это не помогло :-( - person soc; 04.10.2011
comment
Да, я знаю, что мог бы использовать разные имена, но я бы предпочел, чтобы они были одинаковыми. Кстати, вы имели в виду переопределить? - person soc; 04.10.2011