3

なぜこれが間違っているのか、それを解決する方法がわかりません。これが問題を再現する「蒸留された」コードです。助けてください、しかし私は「なぜ」の質問のどれにも感謝しません-それに対する非常に現実的で有効な答えがありますが、それらは独占的で変更できないので、解決策とは無関係です。

object Sandbox {

  // --- Following are really Java interfaces/classes ---
  trait R[X <: U[X,Y], Y <: E[X,Y]];
  class U[X <: U[X,Y], Y <: E[X,Y]] extends R[X,Y];
  class E[X <: U[X,Y], Y <: E[X,Y]] extends R[X,Y];

  trait R2 extends R[U2,E2];
  class U2 extends U[U2,E2] with R2;
  class E2 extends E[U2,E2] with R2;
  // --- End Java interfaces/classes ---

  def trouble[X <: U[X,Y], Y <: E[X,Y], Z <: R[X,Y]](r: Z) {}

  def main(args: Array[String]) {
    trouble(new U());  // Fine
    trouble(new E());  // Fine
    trouble(new U2()); // Not fine, reports:
    /*
     * inferred type arguments [Nothing,Nothing,Sandbox.U2]
     * do not conform to method trouble's type parameter bounds
     * [X <: Sandbox.U[X,Y],Y <: Sandbox.E[X,Y],Z <: Sandbox.R[X,Y]]
     */


    trouble(new E2()); // Not fine, reports:
    /*
     * inferred type arguments [Nothing,Nothing,Sandbox.E2]
     * do not conform to method trouble's type parameter bounds
     * [X <: Sandbox.U[X,Y],Y <: Sandbox.E[X,Y],Z <: Sandbox.R[X,Y]]
     */

    trouble[U2,E2,R2](new U2()); // Fine
    trouble[U2,E2,R2](new E2()); // Fine
  }
}

コンパイラは、指定された単一の引数だけに基づいて、「トラブル」メソッドのX、Y、およびZタイプの引数を推測できないようです。私はそれだけ理解しています-タイプを指定するとき、それはOKですが、それは非常に面倒です。これが問題にならないように、何らかの方法でコンパイラを微調整/支援する方法はありますか?

たぶん私はScalaの型推論システムにあまりにも自信を持っていますが、すべての情報が利用可能です。

前もって感謝します!

4

2 に答える 2

4

あなたはScalaの型システムの推論にあまりにも自信を持っています。これらのより複雑な(特に再帰的な)型定義を操作しようとすればするほど、これを発見することができます。「なぜこれを理解できないのか」を提供できるかどうかはわかりませんが、機能するものを提供することはできます。

タイプのRをパラメーター化しないでください。ただし、サブタイプで宣言する必要がある抽象メンバーにします。

trait R {
    type X <: U[X,Y]
    type Y <: E[X,Y]
}

class U[X0 <: U[X0,Y0],Y0 <: E[X0,Y0]] extends R {
    type X = X0
    type Y = Y0
}
class E[X0 <: U[X0,Y0], Y0 <: E[X0,Y0]] extends R {
    type X = X0
    type Y = Y0
}

trait R2 extends R;
class U2 extends U[U2,E2] with R2
class E2 extends E[U2,E2] with R2

def trouble[X <: U[X,Y], Y <: E[X,Y], Z <: R](r: Z) {}

そうすれば、メインのメソッドのコンパイルは変更されていないことがわかると思います。

余談ですが、コード内のすべてのセミコロンは、意味を変更せずに削除できます。

于 2012-12-07T06:11:39.223 に答える
1

ここで混乱を引き起こしているScalaの型推論の制限については、この回答(およびそこにリンクしている回答)を参照してください。

XY本体(または戻り型)が不要な場合はtrouble、実存型を使用して、それらをまったく参照しないようにすることができます。

def trouble[Z <: R[_, _]](r: Z) {}

それらが必要な場合は、ビューバウンドを使用できます。

def trouble[X <: U[X, Y], Y <: E[X, Y], Z <% R[X, Y]](r: Z) {}

これが機能する理由の説明については、上記のリンク先の回答を参照してください。

于 2012-12-07T19:19:59.573 に答える