Scala: соответствие vararg (повторяющиеся аргументы) по типу хранимых элементов - PullRequest
0 голосов
/ 06 мая 2020

Я недавно начал изучать Scala и сейчас возился с учебниками. Я хотел бы иметь 2 реализации рациональной арифметики. У меня есть черта IRational и 2 класса, реализующие его: Rational и RationalAbstraction. Большая часть функциональности такая же, поэтому я реализую поведение по умолчанию в трейте, но мне нужно получить правильный конструктор - либо для Rational, либо для RationalAbstraction. Для этого у меня есть функция:

def constructorImpl(numerator: Int, denominator: Int, first: IRational, irationals: IRational*): IRational = {
  println(s"first class: ${first.getClass.getSimpleName}, irationals class: ${irationals.getClass.getSimpleName}")
  first match {
    case rational: Rational => irationals match {
      case rationals: Seq[Rational] => new Rational(numerator, denominator)
      case _ => throw new UnimplementedCaseException(this, "constructorImpl", first +: irationals: _*)
    }
    case abstraction: RationalAbstraction => irationals match {
      case abstractions: Seq[RationalAbstraction] => new RationalAbstraction(numerator, denominator)
      case _ => throw new UnimplementedCaseException(this, "constructorImpl", first +: irationals: _*)
    }
  case _ => throw new UnimplementedCaseException(this, "constructorImpl", first +: irationals: _*)
  }
}

К сожалению, это не работает.
case rationals: Seq[Rational] => new Rational(numerator, denominator)
Не соответствует varargs, содержащим Rational, также позволяет RationalAbstraction.
Почему это ? Как сопоставить varargs по типу?
Нужно ли мне писать функцию, которая разворачивает ирациональные числа: _ * по одному и проверяет тип головы (первых элементов)?

Это репозиторий проекта на github: https://github.com/axal25/LearnScalaMavenBasics

Вызов тестового примера функции [256 строк]: https://github.com/axal25/LearnScalaMavenBasics/blob/master/src/main/scala/org/exercises/scala/ool/ObjectOrientedProgramming.scala

Реализация функции [106 строк]: https://github.com/axal25/LearnScalaMavenBasics/blob/master/src/main/scala/org/exercises/scala/ool/arith/ration/IRational.scala

Если у кого-то есть хороший пример материала (учебник), иллюстрирующий, как эти чертовски надоедливые варарги работают в Scala, я был бы признателен.

Изменить:
Цель метода constructorImpl - выбрать правильный конструктор для арифматических c операций (add / +, sub / -. Mul / *, div //).
first: Irational аргумент является 1-м аргументом операция (add, sub, mul, div).
irationals: Irational* аргумент - это 2-й, 3-й, ... n-й аргумент операции (add, sub, mul, div).
Некоторые операции требуют 2 объекты IRational реализации, некоторые требуют 1 объект IRational impl. и, например, Int, но всегда как минимум 1 объект IRational impl. Поэтому выбор правильного конструктора зависит от этих объектов IRational impl и требует, чтобы они оба имели одну и ту же реализацию. Если 2 (или более) объекта реализации IRational имеют разную реализацию (комбинация Rational и RationalAbstraction), мы не знаем, какой конструктор вызывать, поэтому должно возникнуть исключение.

Решение в этой иерархии ( без использования дженериков):

  def constructorImpl(numerator: Int, denominator: Int, first: IRational, irationals: IRational*): IRational = {
    println(s"first class: ${first.getClass.getSimpleName}, irationals class: ${irationals.getClass.getSimpleName}")

    @scala.annotation.tailrec
    def isSeqElementsOfTypeSameAsFirst(first: Any, irationals: Any*): Boolean = irationals match {
      case Seq() => true
      case Seq(head, tail@_*) => {
        if (first.getClass == head.getClass) isSeqElementsOfTypeSameAsFirst(first, tail: _*)
        else false
      }
      case _ => false
    }

    if (isSeqElementsOfTypeSameAsFirst(first, irationals: _*)) {
      first match {
        case rational: Rational => new Rational(numerator, denominator)
        case abstraction: RationalAbstraction => new RationalAbstraction(numerator, denominator)
        case _ => throw new UnimplementedCaseException(this, "constructorImpl", first +: irationals: _*)
      }
    }
    else throw new MixingIRationalImplementationException(first, irationals: _*)
  }

фиксация вопроса: https://github.com/axal25/LearnScalaMavenBasics/commit/c5a113b0361d8632bb39bbfc7ed7f7cd329a2da1
фиксация решения: https://github.com/axal25/LearnScalaMavenBasics/commit/1920128ba2aedac4fa9671311ec56dcc09dc7483

1 Ответ

0 голосов
/ 06 мая 2020

Нужно ли мне писать функцию, которая разворачивает ирациональные числа: _ * по одному и проверяет тип головы (первых элементов)?

Да, вам нужно проверять каждый элемент. irationals может содержать элементы любого подкласса IRational, и не все они должны быть одного и того же подтипа, поэтому вам нужно проверить каждый из них. Но неясно, какова цель irationals, поэтому вопрос требует более подробной информации.

...