Какова мотивация классов типов в Scala?

У меня возникли проблемы с мотивацией использования классов типов в Scala при сравнении с верхними границами типов.

Рассмотрим следующий код:

  case class NumList[T <: Complex](xs: Complex*) {
    def sum = (xs fold new Complex(0, 0))(_ + _)
    def map[U <: Complex](f: Complex => U): NumList[U] = NumList(xs.map(f): _*)
    override def toString = "[" + xs.mkString(", ") + "]"
  }

  case class GenList[T](xs: T*) {
    def sum(implicit num: Numeric[T]) = xs.sum
    def map[U](f: T => U) = GenList(xs.map(f): _*)
    override def toString = "[" + xs.mkString(", ") + "]"
  }

  val r = new Real(2)
  val n = new Natural(10)
  val comps = NumList(r, n, r, n)

  println(comps)
  println("sum: " + comps.sum)
  println("sum * 2: " + comps.map(x => x + x).sum)

  val comps2 = GenList(4, 3.0, 10l, 3d)
  println(comps2)
  println("sum: " + comps2.sum)
  println("sum * 2: " + comps2.map(_ * 2).sum)

Хотя эти два списка решают схожие проблемы, в одном используется числовой класс типов, а в другом используется верхняя граница параметра типа. Я хорошо понимаю технические различия, но мне трудно понять основную мотивацию классов типов. Лучшая мотивация, которую я нашел до сих пор, заключается в следующем:

В то время как подклассы или реализация интерфейсов позволяют вам делать в основном одни и те же проекты, классы типов позволяют вам указывать функции типа для каждого метода, тогда как универсальный класс с типом T и верхней границей U ограничивает T везде, где он используется. . Имея это в виду, классы типов обеспечивают более тонкий контроль над функциями T в универсальных классах.

Есть ли какие-нибудь очень четкие примеры, мотивирующие паттерн?


person Felix    schedule 10.04.2013    source источник


Ответы (1)


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

Предположим, вам нужно определить новый числовой тип MetaNum (со стандартными числовыми операциями), но вы не можете или не хотите делать его подклассом вашего типа Complex по какой-либо причине.

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

Затем вы можете создать GenList[MetaNum] и суммировать его.

Вы не можете сделать это с NumList, потому что MetaNum не Complex. Выбор реализации, который вы сделали при определении NumList, ударит по вам, когда вы попытаетесь обобщить свою операцию/структуру данных во второй момент.

Заключение
Классы типов дают вам больше свободы для расширения вашего поведения независимо от иерархических соображений за счет дополнительной сложности и шаблонного кода.

Я не могу сказать, имели ли вы то же самое в своем вопросе.

person pagoda_5b    schedule 10.04.2013
comment
Это точное рассуждение. В целом классы типов могут быть более краткими, чем в Scala. То, как они закодированы, позволяет использовать их с гораздо большей гибкостью, чем в чем-то вроде ванильного Haskell, но реализация Haskell гораздо более лаконична. Другим хорошим примером является добавление чего-то вроде сериализации в вашу иерархию, добавление интерфейса в верхнюю часть иерархии сломает все ваши старые классы. Использование классов типов позволяет реализовать функциональные возможности поэтапно и конкретно только для необходимых типов. - person jroesch; 10.04.2013
comment
Как сказал @jroesch, полезно подчеркнуть тот факт, что классы типов реализованы в scala как шаблон (то есть не как языковая функция), но концепция взята из других языков (например, haskell), где эта функция встроена в сам язык. Например, haskell не является объектно-ориентированным языком, в нем нет механизма наследования, поэтому функция класса типов используется для получения общей функциональности путем реализации пользовательских функций для разных типов данных. Вот почему классы типов могут показаться излишними в scala, где функциональность пересекается с наследованием объектов. - person pagoda_5b; 11.04.2013
comment
Очень хороший. Я оставил это в покое на некоторое время и вернулся к вопросу самостоятельно, пытаясь мотивировать его. Я привел очень похожий аргумент. Хороший! - person Felix; 27.05.2013