8

私の頭をanother questionに割いている間、私はさまざまな謎を抱いていました。これはそのうちの一つです:表現型を型メンバーとして実装できません

次のようにエラーがある
trait Sys[S <: Sys[S]] { 
    type Peer <: Sys[Peer] 
} 

trait Fenced { 
    type Peer <: Sys[Peer] 
} 

def makeFence[S <: Sys[S]] = new Fenced { type Peer = S#Peer } 

error: overriding type Peer in trait Fenced with bounds >: Nothing <: Sys[this.Peer]; 
type Peer has incompatible type 
     def makeFence[S <: Sys[S]] = new Fenced { type Peer = S#Peer } 
                ^

はなぜ?レックスの答えはFencedオブジェクトを構築することが可能となりますが


(また、Sysに自己型_:S =>を追加しようとした問題ではありませんでした)、それは本当に表現型の文字で、私が持っている問題を解決しませんタイププロジェクション(S#Peer)を使用すると失われます。私はより厳しい制約を課す別のシナリオを考え出しました。私はまだあなたが探しているものを制約完全に一定ではないよ

trait Test[S <: Sys[S]] { 
    def make[T <: Sys[T]](): Unit 

    make[S#Peer]() 
} 

error: type arguments [S#Peer] do not conform to method make's type 
     parameter bounds [T <: Sys[T]] 
       make[S#Peer]() 
       ^
+0

私は基本的な問題は '形質A [B <:Sys [B]]'(これは問題ありません)と '形質A {タイプB <:Sys [B]}すべてのトラブル)。しかし、私は実際に型メンバーで作業する必要があります、私は私のケースでは型パラメータを導入することはできません。 –

+0

あなたは何を達成しようとしていますか? 「S#ピア」は「S」からの「ピア」であるが、「フェンス」は、(サーフェスレベルの)非互換性を生成する「S」ではなく「ピア」であることをピアに望んでいる。論理的に互換性がないかどうかは、型をシンプルなエイリアスまたは所有権のステートメントとして表示するかどうかによって決まります。残念なことに、これに関してScalaは完全に一貫していません。 「Fenced」には「Sys」型の型があると言うだけですか? –

+0

@RexKerr - その意図がはっきりしない場合は申し訳ありません。リンクされた質問は全体の文脈を与える。基本的に、私が必要と思うものは、 'S <:Sys [S] '以外の追加情報なしで、外部システムを渡すことができるように、外部システムのタイプメンバーのみを使用して、他のピアシステムを完全に埋め込むことができます。私はここでタイプの予測の限界にぶつかっています。問題は、外側のシステムの消費者の中で同輩のタイプを復活させることは不可能であると言ってこれを説明しようとします。 –

答えて

3

が、ここでは1つの可能性である:私は、これが問題の核心だと思います(!と必要)

trait Sys[S <: Sys[S]] { 
    type Peer <: Sys[Peer] 
} 

trait Fenced { 
    type MySys <: Sys[MySys] 
    type Peer = MySys#Peer 
} 

def makeFence[S <: Sys[S]] = new Fenced{ type MySys = S } 

これはあなたを与えますPeerと元の外側のタイプFencedの両方へのアクセス。 Fencedがこれを行う可能性があるのか​​、それとも外側のタイプ間で抽象化する必要があるのか​​はわかりません。

+0

非常に面白いアプローチです。型パラメータを型メンバーに移動します。はい、「フェンス」に両方のタイプを持つことに問題はありません。私はこれをすべての結果に向けて演奏しなければならないが、少なくともこれは新しい考えである。 –

+0

これは、 'Fenced'の' Peer'型メンバーの 'Peer <:Sys [Peer]'制約を削除するため、 'Sys'の不変量' S'でのみ機能します。 –

+0

これは有効な回避策ではないとは言いませんが、一般的に、このアプローチでは 'val f = makeFence [X]'を使用すると 'f.Peer <:Sys [f] .Peer] '(' X'が具体的な 'Peer'を持っている場合を除いて、しかし私は制約としてどのようにフレーズするかわかりません)。 –

3

Sysの型パラメータは共変できますか?たとえば、これはコンパイル:我々は(唯一のREPLのコピー&ペーストの便宜のためにオブジェクトにラップ)次がある場合

trait Sys[+S <: Sys[S]] { type Peer <: Sys[Peer] } 
trait Fenced { type Peer <: Sys[Peer] } 

def makeFence[S <: Sys[S]] = new Fenced { type Peer = S#Peer } 

は今:

を:

object Example { 
    case class SysX(i: Int) extends Sys[SysX] { type Peer = SysY } 
    case class SysY(j: Int) extends Sys[SysY] { type Peer = SysX } 
} 

import Example._ 

を私は期待通りに動作します

scala> val fenceX = makeFence[SysX] 
fenceX: java.lang.Object with Fenced{type Peer = Example.SysX#Peer} = ... 

scala> val y: fenceX.Peer = SysY(1) 
y: fenceX.Peer = SysY(1) 

scala> val y: fenceX.Peer = SysX(1) 
<console>:15: error: type mismatch; 
found : Example.SysX 
required: fenceX.Peer 
     val y: fenceX.Peer = SysX(1) 

あなたは何を望んでいますか?

+0

トラヴィスは申し訳ありませんが、「S」は不変のままです:-( –

+0

@Travis Hi Travis。その変種であれば動作しませんか? – Jatin

関連する問題