4

要するに: 以下はコンパイルされません (以下の理由)。どうすれば動作させることができますか?

trait Simulator {
  type CM[T]
  def useCM(v: CM[_])
}

case class CMH[S <: Simulator,T](cm: S#CM[T])

class SimIterator[S <: Simulator](val sim: S, val cmhs: Seq[CMH[S,_]]) {
  cmhs foreach { cmh => sim.useCM(cmh.cm) }
  /*
  compile time error:
   type mismatch; found : cmh.cm.type (with underlying type S#CM[_$2]) required:
   SimIterator.this.sim.CM[_] Note: _$2 <: Any (and cmh.cm.type <: S#CM[_$2]),
   but type CM is invariant in type T. You may wish to define T as +T instead.
   (SLS 4.5)
  */
}

構造の背後にある考え方は、後者が一般的なタスクを処理する場所から固有の動作をCMH隠すことです。のインスタンスを持たずに、値を強制的に正しい型にするために使用されます。TSimIteratorSCMHSimulator

では、foreachに関連するサブタイプの問題があるようCMです。S#CMが必要な具体的なタイプの場合sim.CM =:= S#CM。ただし、次の点を見てください。

object Test extends Simulator {
  type CM[T] = Option[T]
  def useCM(v: CM[_]) = println(v)
  def mkCM[T]: CM[T] = None

  CMH[Simulator,AnyRef](mkCM[AnyRef])
}

これで、 any と一緒CMHに a に渡すことができます。したがって、どうやら の入力は十分に制限的ではありません。どのように表現 (および使用) できますか?SimIteratorSimulatorSimIteratorS =:= sim.type

アップデート

これは機能しますが、コンストラクターで使用することはできません (不正な依存メソッド タイプ: パラメーターが同じセクションまたは前のセクションの別のパラメーターの型に表示されます)

class SimIterator(val sim: Simulator) {
  def doIt(cmhs: Seq[CMH[sim.type,_]]) {
    cmhs foreach { cmh => sim.useCM(cmh.cm) }
  }
}

上の例は機能しますが、私が望むものではありません。cmhs建設時に渡す必要があります。

4

2 に答える 2

2

次のように、抽象型メンバーを型パラメーターに移動することで、問題を簡単に修正できます。

trait Simulator[CM[_]] {
  def useCM(v: CM[_])
}

case class CMH[CM[_]](cm: CM[_])

class SimIterator[S <: Simulator[CM], CM[_]](val sim: S, val cmhs: Seq[CMH[CM]]) {
  cmhs foreach { cmh => sim.useCM(cmh.cm) }
}

そうすれば、型プロジェクションの使用を避けることができます。本当に CM を型メンバーとして保持する必要がある場合は、型プロジェクションが必要な場合とその理由をより詳細に説明してください。

編集/更新

「運命のベーカリー」へようこそ!;-)

この場合、2 つの解決策があります。

まず、型に直接アクセスできるように、Iterator を Cake に入れます

case class CMH[CM[_]](cm: CM[_])

trait Cake {
  type CM[_]

  trait Simulator {
    def useCM(v: CM[_])
  }

  class SimIterator[S <: Simulator](val sim: S, val cmhs: Seq[CMH[CM]]) {
    cmhs foreach { cmh => sim.useCM(cmh.cm) }
  }
}

または 2番目に、Iterator を他のクラスにカプセル化し、パス依存型にアクセスできるようにします。

trait Cake {
  type CM[_]

  trait Simulator {
    def useCM(v: CM[_])
  }
}

case class CMH[CM[_]](cm: CM[_])

class SimIteratorBuilder[C <: Cake](val cake: Cake) {
  class SimIterator(val sim: cake.Simulator, val cmhs: Seq[CMH[cake.CM]]) {
    cmhs foreach { cmh => sim.useCM(cmh.cm) }
  }
}

あなたがケーキに入ったら、それを逃れる方法はありません!

于 2013-04-26T21:19:13.460 に答える