Подтвердить что ты не робот

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

4b9b3361

Ответ 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-версии вашего сотрудника.