Почему я не могу преобразовать этот тип в общий? - PullRequest
0 голосов
/ 25 мая 2018
def linearInterpolation(weights: Seq[Double], points: Seq[Seq[Double]]) : Seq[T] = {

  weights.zip(points).map(
    weight_point => weight_point._2.map(coordinate => weight_point._1 * coordinate)
  ).reduce((point_a : Seq[Double], point_b : Seq[Double]) => point_a.zip(point_b).map(coordinate_points => (coordinate_points._1 + coordinate_points._2).asInstanceOf[T]))

}

В этом коде я пытаюсь преобразовать тип возврата a Seq[Double] в Seq[T].При выполнении вызова T может быть, например, Double или Int.

Это преобразование должно быть реализовано благодаря .asInstanceOf[T].

Ошибкам

Код компилируется.

Но если я его выполняю, я получаю следующие ошибки:

Ошибка: (25, 61) несоответствие типов;найдено: (Seq [Double], Seq [Double]) => Seq [T] требуется: (Seq [Any], Seq [Any]) => Seq [Any]) .reduce ((point_a: Seq [Double],point_b: Seq [Double]) => point_a.zip (point_b) .map (координаты_пунктов => (координаты_пунктов._1 + координаты_пункта._2) .asInstanceOf [T]))

Ошибка: (25, 13)несоответствие типов;найдено: Seq [Любой] требуется: Seq [T]) .reduce ((point_a: Seq [Double], point_b: Seq [Double]) => point_a.zip (point_b) .map (координата_точки => (координата_точки._1 +координат_пунктов._2) .asInstanceOf [T]))

Вопрос

Почему сбой выполнения?Как добиться этого преобразования из Seq[Double] в Seq[T]?

Ответы [ 3 ]

0 голосов
/ 25 мая 2018

Я дополняю ответ от Алексея.Я бы объявил fromDouble как неявный и создал бы функции конвертера как неявные значения, и вы могли бы использовать вашу функцию так, как вы ее спроектировали.Пример:

object DoubleConverters {
  implicit val doubleToDouble: Double => Double = identity
  implicit val doubleToInt: Double => Int = _.round.toInt
}

def linearInterpolation[T](weights: Seq[Double], points: Seq[Seq[Double]])(implicit converter: Double => T) : Seq[T] =
  weights.zip(points)
     .map(weight_point => weight_point._2.map(coordinate => weight_point._1 * coordinate))
     .reduce((point_a: Seq[Double], point_b: Seq[Double]) => point_a.zip(point_b).map(coordinate_points => (coordinate_points._1 + coordinate_points._2)))
     .map(converter)

// sample call
val result = linearInterpolation[Double]( weights = Seq(1.1, 1.3), Seq(Seq(1.1, 1.2), Seq(1.3, 1.4)))

// образец вызова val result = linearInterpolation [Double] (вес = Seq (1.1, 1.3), Seq (Seq (1.1, 1.2), Seq (1.3, 1.4)))

0 голосов
/ 25 мая 2018

То же самое с классом типа:

trait DoubleConverter[T] {
    def convert(d: Double): T
}

object DoubleConverter {
    implicit val doubleToInt: DoubleConverter[Int] = new DoubleConverter[Int] {
        override def convert(d: Double): Int = d.round.toInt
    }

    implicit val doubleToDouble: DoubleConverter[Double] = new DoubleConverter[Double] {
        override def convert(d: Double): Double = d
    }
}

def linearInterpolation[T](weights: Seq[Double], points: Seq[Seq[Double]])(implicit converter: DoubleConverter[T]) : Seq[T] =
    weights.zip(points)
       .map(weight_point => weight_point._2.map(coordinate => weight_point._1 * coordinate))
       .reduce((point_a: Seq[Double], point_b: Seq[Double]) => point_a.zip(point_b).map(coordinate_points => (coordinate_points._1 + coordinate_points._2)))
       .map(converter.convert)

// sample call
val result = linearInterpolation[Int]( weights = Seq(1.1, 1.3), Seq(Seq(1.1, 1.2), Seq(1.3, 1.4)))

Видите, что использование остается прежним.И мы избегаем случайного использования Double => Int.

0 голосов
/ 25 мая 2018

Во-первых, нет, этот код не компилируется: это ошибки компиляции, а не исключения времени выполнения.Вы можете видеть, потому что он начинается с Error:, указывает на точную позицию в исходном коде (исключения имеют только номер строки), и нет трассировки стека.

Теперь, если он скомпилирован, он не будетэто не работает, но это отдельная проблема.

Так почему же он не компилируется?Тип weights.zip(points).map(...) равен Seq[Seq[Double]], поэтому подпись reduce становится reduce[A1 >: Seq[Double]](op: (A1, A1) => A1): A1.Обратите внимание, что типы возврата и аргумента аргумента reduce должны совпадать, а в вашем случае они не совпадают (у вас есть (Seq[Double], Seq[Double]) => Seq[T]).Само по себе этого не достаточно для компиляции.

Ожидаемый тип всего weights.zip(points).map(...).reduce(...) равен Seq[T], поэтому компилятору нужно выбрать A1, то есть:

  1. супертип Seq[Double] для удовлетворения ограничения

  2. подтип Seq[T] для соответствия типов возвращаемых данных

Такиетип не существует (без дополнительных ограничений на T), но если он это сделает, это будет Seq[SomeType], и это все, что должен получить компилятор.Почему в конечном итоге отображается Any, я действительно не вижу.

Как добиться этого преобразования из Seq [Double] в Seq [T]?

Это имеет больше смысла, если у вас есть weights: Seq[T], points: Seq[Seq[T]].В этом случае используйте Numeric.Существует довольно много ответов о переполнении стека и за его пределами, объясняющих, как, например, Scala-эквивалент числа Java .

Для weights: Seq[Double], points: Seq[Seq[Double]] я бы просто добавил функцию Double => T в качестве дополнительного аргумента:

def linearInterpolation(weights: Seq[Double], points: Seq[Seq[Double]])(fromDouble: Double => T) : Seq[T] = {

  weights.zip(points).map(
    weight_point => weight_point._2.map(coordinate => weight_point._1 * coordinate)
  ).reduce((point_a : Seq[Double], point_b : Seq[Double]) => point_a.zip(point_b).map(coordinate_points => coordinate_points._1 + coordinate_points._2)).map(fromDouble)

}
...