У меня возникли проблемы с мотивацией использования классов типов в 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 в универсальных классах.
Есть ли какие-нибудь очень четкие примеры, мотивирующие паттерн?