Scala - Пример типа. Как объяснить преимущества?
Итак, я показывал коллеге/другу пример шаблона типа в Scala. Это выглядит так:
case class Song(name: String, artist: String)
case class Address(street: String, number: Int)
trait LabelMaker[T] {
def output(t: T): String
}
object LabelMaker {
implicit object addressLabelMaker extends LabelMaker[Address] {
def output(address: Address) = {
address.number + " " + address.street + " street"
}
}
implicit object songLabelMaker extends LabelMaker[Song] {
def output(song: Song) = {
song.artist + " - " + song.name
}
}
def label[T : LabelMaker](t: T) = implicitly[LabelMaker[T]].output(t)
}
Что можно использовать следующим образом:
import LabelMaker._
println(label(new Song("Hey Ya", "Outkast"))) // Outkast - Hey Ya
println(label(new Address("Smithsonian", 273))) // 273 Smithsonian street
Это не лучший пример, и в ретроспективе я бы хотел, чтобы я придумал лучший. Показывая ему, он ответил встречным примером и спросил, какие преимущества шаблон шаблона фактически приводит к таблице:
case class Song(name: String, artist: String)
case class Address(street: String, number: Int)
object LabelMaker {
def label(address: Address) = {
address.number + " " + address.street + " street"
}
def label(song: Song) = {
song.artist + " - " + song.name
}
}
import LabelMaker._
println(label(new Song("Hey Ya", "Outkast"))) // Outkast - Hey Ya
println(label(new Address("Smithsonian", 273))) // 273 Smithsonian street
Я изо всех сил пытался ответить на это правильно, и это заставило меня понять, что я не совсем понимаю, что выигрыш составил 100%. Я понимаю их реализацию и очень локализованные преимущества, когда кто-то их использует, но на самом деле кратко объяснить их довольно сложно. Может кто-нибудь мне помочь? И, возможно, на моем примере, чтобы действительно показать преимущества.
Ответы
Ответ 1
Typeclasses фиксируют понятие ретроактивной расширяемости. При перегрузках статических методов вы должны определить их все сразу в одном месте, но с помощью типов типов вы можете определять новые экземпляры в любое время для любых новых типов в любых модулях.
Например,
object LabelMaker {
// ... your original cases here ...
def label[T : LabelMaker](t: T) = implicitly[LabelMaker[T]].output(t)
}
// somewhere in future
object SomeModule {
import LabelMaker._
case class Car(title: String)
implicit object carLabelMaker extends LabelMaker[Car] {
def output(car: Car) = car.title
}
}
object Main extends App {
import LabelMaker._
import SomeModule._
println(label(Car("Mustang")))
}
Ответ 2
Тип вывода и состав классов типов:
implicit def tupleLabel[A: LabelMaker,B: LabelMaker] = new LabelMaker[(A,B)]{
def output(tuple: (A,B)) =
implicitly[Label[A]].label(tuple._1) + " and " + implicitly[Label[B]].label(tuple._2)
}
Это, очевидно, полезно и не будет работать в Java-версии вашего сотрудника.