2009-02-26 24 views
10

メンバー型がScalaでどのように機能するのか、型をどのように関連付けるべきかを知りたいと思います。型パラメータとScala型のメンバー型

1つのアプローチは、関連付けられたタイプをタイプパラメータにすることです。このアプローチの利点は、タイプの分散を処方できることです。サブタイプがタイプを変更しないことを確信できます。欠点は、関数の型から型パラメータを推論できないということです。

第2のアプローチは、私はサブタイプ関連するタイプに境界を規定することができないので、私は、関数パラメータの型を使用できないという問題を有している関連型の第2種類の部材を作製することです具体例は次のようになり

:(X、X位のTがxTの有する任意の関連しないかもしれないときにX):

Iは

trait DFA[S] { /* S is the type of the symbols in the alphabet */ 
    trait State { def next(x : S); } 
    /* final type Sigma = S */ 
} 
(typeパラメータなしであってもよい)のDFAのための形質を有します

と実行するための関数を作成したいこの入力シーケンスの上にDFA、と私は

  • 機能は、入力シーケンスの種類としては何も<% Seq[alphabet-type-of-the-dfa]を取る必要がありますしたい
  • 型パラメータを指定する必要はありません、関数呼び出し側は、すべてを推測しなければならない
  • 私は思います具体的なDFA型で呼び出す関数と同じです(ただし、DFAの型パラメータを持たない解決策があれば問題ありません)。
  • アルファベットの型は拘束されていない必要があります。

    def runDFA[S, D <: DFA[S], SQ <% Seq[S]](d : D)(seq : SQ) = .... 
    

    この作品:私はこれを試したサブタイプではありません異なるアルファベットタイプで

シャアのためだけでなく、未知のユーザ定義クラスのDFA)

  • のDFAがなければなりませんただし、タイプSはここでは推測されないので、各コールサイトに型パラメータリスト全体を記述する必要があります。

    def runDFA[D <: DFA[S] forSome { type S }, SQ <% Seq[D#Sigma]](... same as above 
    

    これは私も、型パラメータを削除抽象型シグマを作成し、その型を結合しようとした

    (Dを???(それは何ですか?)を入力するには、無効な循環参照を)動作しませんでした具体的なクラスではrunDFAは

    def runDFA[D <: DFA, SQ <% Seq[D#Sigma]](... same as above 
    

    ようになりますが、これは必然的に同様の問題に遭遇し、 "型の不一致:dfa.Sigmaを期待し、D#Sigmaだ"

    任意のアイデア?ポインタ?

    編集:

    答えがこれを行うための簡単な方法がない示しているように、誰かがそれは不可能であり、何がそれが働いたように変更しなければならないであろう理由で、より手の込んだだろうか?

    私がrunDFAをフリー関数(メソッドではない)にしたい理由は、オートマトンの最小化、標準的な言語操作、NFAからDFAへの変換、言語分解などの他の同様の関数を必要とし、このクラス内のクラスは、オブジェクト指向設計のほぼすべての原則に反しています。

  • +0

    うわー、あなたはこれを意味すると思った:http://www.huygens-fokker.org/scala/ – MusiGenesis

    答えて

    3

    まず第一に、あなたは、[パラメータ化SQに<%配列を必要としません。 S]。メソッドパラメータをSeq [S]として記述します。 SQ <%Seq [S]の場合、そのインスタンスはSeq [S]に暗黙的に変換されます(つまり、<%の意味です)。Seq [S]として渡されると、コンパイラは自動的に変換を挿入します。

    さらに、JorgeはDの型パラメータについて説明し、DFA保留に関するメソッドにしました。内部クラスがScalaで動作するため、はDFAにrunDFAを置くことを強くお勧めします。パスに依存した型指定が機能するまでは、いくつかの外部クラスの内部クラスを扱うことは少し苦しいことがあります。

    は、だから今は

    trait DFA[S]{ 
        ... 
    
        def runDFA(seq : Seq[S]) = ... 
    } 
    

    を持っており、runDFAはのために型パラメータを推測することが比較的容易突然のすべてです:それは、いずれかを持っていません。

    3

    Scalaの型推論は、しばしば望ましいものになります。

    あなたのDFA特性の中にこの方法を使用できない理由はありますか?

    def run[SQ <% Seq[S]](seq: SQ) 
    

    後でDのPARAMを必要としない場合、あなたはまた、それなしで、あなたのメソッドを定義してみてください:

    def runDFA[S, SQ <% Seq[S]](d: DFA[S])(seq: SQ) = ... 
    
    0

    方法2と異なる点についていくつかの有用な情報:

    型崩れguideから:あなたが依存型を作ることができない

    型パラメータがなければ、例えば

    trait Generic[A] { 
        type Repr 
        def to(value: A): Repr 
        def from(value: Repr): A 
    } 
    
    import shapeless.Generic 
    def getRepr[A](value: A)(implicit gen: Generic[A]) = 
        gen.to(value) 
    

    ここで返されるタイプは、入力タイプA(暗黙指定はAに依存するため)によって異なります。

    case class Vec(x: Int, y: Int) 
    case class Rect(origin: Vec, size: Vec) 
    getRepr(Vec(1, 2)) 
    // res1: shapeless.::[Int,shapeless.::[Int,shapeless.HNil]] = 1 :: 2 :: 
        HNil 
    getRepr(Rect(Vec(0, 0), Vec(5, 5))) 
    // res2: shapeless.::[Vec,shapeless.::[Vec,shapeless.HNil]] = Vec(0,0) 
        :: Vec(5,5) :: HNil 
    

    型メンバなしで、これは不可能であろう:私たちが持っていただろう

    trait Generic2[A, Repr] 
    def getRepr2[A, R](value: A)(implicit generic: Generic2[A, R]): R = 
        ??? 
    

    がeffec vely getReprは無用作り、 型パラメータとしてgetReprにREPRの目標値を渡します。この点から、 は、型パラメータが "入力"として有用であり、 型のメンバが "出力"として有用であることが分かります。

    詳細については、シェイプレスguideをご覧ください。

    関連する問題