20

そこで、同僚/友人に 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%の利益をよく理解していないことに気づきました. 他の誰かがそれらを使用する場合、それらの実装と非常にローカライズされた利点を理解していますが、実際にそれらを簡潔に説明することは非常に困難です. 誰でも私を助けることができますか?そして、おそらく私の例を拡張して、その利点を実際に示してください。

4

2 に答える 2

24

型クラスは、遡及的拡張性の概念を捉えています。静的メソッドのオーバーロードでは、一度にすべてを 1 か所で定義する必要がありますが、型クラスを使用すると、任意のモジュールの新しい型に対していつでも新しいインスタンスを定義できます。例えば

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")))
}
于 2012-12-19T23:56:58.597 に答える
0

型推論と型クラスの合成:

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 バージョンでは機能しません。

于 2012-12-20T10:08:54.360 に答える