型の上限と比較するときに、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)
これら 2 つのリストは同様の問題を解決しますが、一方は数値型クラスを使用し、もう一方は型パラメーターの上限を使用します。技術的な違いはよく理解できますが、型クラスの核となる動機にたどり着くのに苦労しています。これまでに見つけた最高の動機は次のとおりです。
インターフェイスをサブクラス化または実装すると、ほとんど同じ設計を行うことができますが、型クラスを使用すると、メソッドごとに型の機能を指定できますが、型T
と上限を持つジェネリック クラスは、それが使用されるすべての場所でU
制約を受けます。T
これを念頭に置いて、型クラスはジェネリック クラスの T の機能をよりきめ細かく制御します。
パターンの動機となる非常に明確な例はありますか?