2013-04-10 7 views
9

型上の境界と比較するとき、Scalaで型クラスの使用を動かすのに問題があります。これら二つのリストが同様の問題を解決しながら1が数値型クラスを使用し、他の種類のパラメータの上限を使用して、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のフィーチャをより細かく制御します。

パターンを動かす非常に明確な例はありますか?

答えて

9

主要な側面を簡素化しようとすると、タイプクラフトはクラス階層とは独立して動作を収集しようとします。

新しい数値型MetaNum(標準的な数値演算で)を定義する必要があるとしますが、何らかの理由でそれをComplexタイプのサブクラスにすることはできません。

Numeric typeclassでは、必要な操作を提供して、MetaNumに適切なインスタンスを提供するだけで済みます。

次に、GenList[MetaNum]を作成して合計することができます。

MetaNumComplexではないため、NumListではこれを行うことはできません。 NumListを定義するときの実装選択は、操作/データ構造をもう一度一般化しようとしたときにあなたに刺さるでしょう。

結論
型クラスはあなたにいくつかの追加の複雑さと決まり文句の費用で、階層的な考察から独立して自分の行動を拡張するために多くの自由を与えます。

あなたの質問に同じ意味があるかどうかはわかりません。

+2

これは正確な推論です。一般的に、型クラスはScalaにあり、より簡潔にすることができます。彼らはエンコードされているので、はるかに柔軟に使用できるようになり、vanilla Haskellのようなものになる可能性がありますが、Haskellの実装ははるかに簡潔です。もう一つの良い例は、あなたの階層にシリアル化のようなものを追加することです。階層の最上部へのインタフェースを追加すると、古いクラスがすべて破損します。型クラスを使用すると、機能を段階的に、具体的には必要な型だけに実装できます。 – jroesch

+2

@jroeschと同じように、タイプクオをパターン(すなわち言語機能ではない)としてスカラーで実装しているという事実を強調するのは有益ですが、その概念が埋め込まれている他の言語(例えばhaskell)言語そのもの。例えば、haskellはOO言語ではなく、継承メカニズムはないため、異なる型のカスタム関数実装によって共通の機能を派生させるためにtypecass機能が使用されます。そのため、オブジェクト継承と機能が重複しているところで、型付けがスカラー上で重複しているように見えることがあります。 –

+0

非常に良い。私はこれをしばらく残して、自分の疑問に戻って動機付けようとしました。私は非常によく似た議論を思いついた。ニース! – Felix

関連する問題