Как ковариация работает в простой функции - PullRequest
2 голосов
/ 27 сентября 2019

Я пытаюсь просто использовать принцип ковариации Scala.Я хотел бы, чтобы приведенные ниже методы max и sum работали с List из Int, Double или любым другим Numeric типом.Код ниже возвращает следующую ошибку:

type mismatch;
found: Int(2)
required: T1 
in max(List(2,3,4))
object Main extends App {

  class utils[+T1 <: Ordered[T1], +T2 <: Numeric[T1]] {

    def max(input_list: List[T1]): T1 = {

      def inside_max(i: Int, current_max: T1): T1 = {
        if (i >= input_list.size) current_max
        if (input_list(i) < current_max) {
          inside_max(i + 1, current_max: T1)
        } else {
          inside_max(i + 1, input_list(i))
        }
      }

      inside_max(0, input_list(0))
    }

    def sum(input_list: List[T2]): T2 = {

      def inside_sum(i: Int, current_sum: T2): T2 = {
        if (i >= input_list.size) current_sum
        val new_sum: T2 = implicitly[Numeric[T2]](Numeric[T2]).plus(current_sum, input_list(i))
        inside_sum(i + 1, new_sum)
      }

      inside_sum(1, input_list(0))
    }

    max(List(2,3,4))

  }

}

1 Ответ

3 голосов
/ 27 сентября 2019

Вы смешиваете дисперсию с подтипом и классами типов , это разные понятия.

В этом случае вам действительно нужно толькоиспользуйте Numeric класс типов .

object Utils {
  def max[T : Ordering](list: List[T]): Option[T] = {
    import Ordering.Implicits._

    @annotation.tailrec
    def loop(remaining: List[T], currentMax: T): T =
      remaining match {
        case Nil =>
          currentMax

        case t :: tail =>
          val newMax =
            if (t >= currentMax)
              t
            else
              currentMax

          loop(
            remaining = tail,
            newMax
          )
      }

    list match {
      case Nil => None
      case t :: tail => Some(loop(remaining = tail, currentMax = t))
    }
  }

  def sum[T : Numeric](list: List[T]): T = {
    import Numeric.Implicits._

    def loop(remaining: List[T], acc: T): T =
      remaining match {
        case Nil =>
          acc

        case t :: tail =>
          loop(
            remaining = tail,
            acc + t
          )
      }

    loop(remaining = list, acc = Numeric[T].zero)
  }
}

, который вы можете использовать следующим образом:

Utils.sum(List(1, 2, 3))
// res: Int = 6

Utils.sum(List.empty[Int])
// res: Int = 0

Utils.max(List.empty[Int])
// res: Option[Int] = None

Utils.max(List(1, 2, 3))
// res: Option[Int] = Some(3)
...