1

私は Scala を初めて使用します。型境界を使用して、次のコードでコードの重複を回避しようとしています (無関係なものは削除されています)。

trait StandardStep1[-I1] {
  def next_step(i:I1):StandardStep2
}

trait StandardStep2

trait UniqueStep1[-I1] extends StandardStep1[I1] {
  def next_step(i:I1):UniqueStep2
}

trait UniqueStep2 extends StandardStep2

class DoubleStandardStep1[-IL,-IR](left:StandardStep1[IL], right:StandardStep1[IR]) extends StandardStep1[(IL,IR)] {
  def next_step(i:(IL,IR)) = {
    val (i_left, i_right) = i
    val new_left = left.next_step(i_left)
    val new_right = right.next_step(i_right)
    new DoubleStandardStep2(new_left, new_right)
  }
}

class DoubleStandardStep2(left:StandardStep2, right:StandardStep2) extends StandardStep2

class DoubleUniqueStep1[-IL,-IR](left:UniqueStep1[IL], right:UniqueStep1[IR]) extends UniqueStep1[(IL,IR)] {
  def next_step(i:(IL,IR)) = {
    val (i_left, i_right) = i
    val new_left = left.next_step(i_left)
    val new_right = right.next_step(i_right)
    new DoubleUniqueStep2(new_left, new_right)
  }
}

class DoubleUniqueStep2(left:UniqueStep2, right:UniqueStep2) extends UniqueStep2

説明:

StandardStep1あるステート マシンのステップを表し、与えられた入力に対してnext_stepを与える操作があります。StandardStep2

UniqueStep1は、呼び出されたときにStandardStep1を与える特別なタイプであり、明らかにそのために継承する必要があります。UniqueStep2next_stepUniqueStep2StandardStep2

ここで、DoubleStepラッパーを作成する必要がありました。sDoubleStandardStep1もラップし、呼び出されたときにStandardStep1a を返します。 同じことを行いますが、 を返します。DoubleStandardStep2next_stepDoubleUniqueStep1DoubleUniqueStep2

*DoubleStep* の実装にはnext_step明らかなコードの重複があります。入力を分割しi_lefti_rightラップされnext_stepたステップを同じ方法で呼び出します。

コードのこの部分を実行する一般的な抽象DoubleStep1を作成することにより、このコードの重複を排除する方法を考えました。

object DoubleStepHelper {
  def next_step_args[IL,IR,SL <: StandardStep1[IL],SR <: StandardStep1[IR]](left:SL,right:SR)(i:(IL,IR)) = { 
    val (i_left, i_right) = i
    val new_left = left.next_step(i_left)
    val new_right = right.next_step(i_right)
    (new_left, new_right)
  }
}

class DoubleStandardStep1[-IL,-IR](left:StandardStep1[IL], right:StandardStep1[IR]) extends StandardStep1[(IL,IR)] {
  def next_step(i:(IL,IR)) = {
    ((l,r) => new DoubleStandardStep2(l,r)).tupled(DoubleStepHelper.next_step_args(left,right)(i))
  }
}

class DoubleStandardStep2(left:StandardStep2, right:StandardStep2) extends StandardStep2


class DoubleUniqueStep1[-IL,-IR](left:UniqueStep1[IL], right:UniqueStep1[IR]) extends UniqueStep1[(IL,IR)] {
  def next_step(i:(IL,IR)) = {
    ((l,r) => new DoubleUniqueStep2(l,r)).tupled(DoubleStepHelper.next_step_args(left,right)(i))
  }
}

class DoubleUniqueStep2(left:UniqueStep2, right:UniqueStep2) extends UniqueStep2

このコード (scala 2.9.2) をコンパイルしようとすると、次のメッセージで失敗します。

型の不一致;
 見つかった: (this.StandardStep2、this.StandardStep2)
 必須: (this.UniqueStep2、this.UniqueStep2)
    ((l,r) => new DoubleUniqueStep2(l,r)).tupled(DoubleStepHelper.next_step_args(left,right)(i))
                                                                                            ^

は値DoubleStepHelper.next_step_argsを返すと想定されているため、これが発生すると想定しています。(StandardStep2, StandardStep2)DoubleUniqueStep2

この問題を解決する方法を考えてもらえますか? DoubleStepHelpernext_step_args が(UniqueStep2, UniqueStep2)ifSLを返し、SRから継承する可能性があることをコンパイラに伝える方法はUniqueStep1?

優れた機能として、 の結果の型を(SL.next_step, SR.next_step)next_step_argsのように定義できることがあります。これは、戻り値の型が および の特定の関数 ( next_step )の戻り値の型から構築されることを意味します。SLSR

「ビュー」境界は何らかの方法で解決できますか?

asInstanceOfを使用してキャストを強制することもできますが、これは見苦しく見えます。

ありがとう

4

1 に答える 1

0

素敵な解決策を見つけました。次のステップの型が型パラメータとして与えられる とを作成AbstractStep1しました。AbstractDoubleStep1

次に、次のステップがStandardStep2またはである場合に、このクラスから継承できUniqueStep2ます。

コードは次のとおりです。

trait AbstractStep1[-I,+S2] {
  def next_step(i:I):S2
}

trait StandardStep1[-I] extends AbstractStep1[I,StandardStep2]

trait StandardStep2

trait UniqueStep1[-I] extends AbstractStep1[I,UniqueStep2] with StandardStep1[I]

trait UniqueStep2 extends StandardStep2

abstract class AbstractDoubleStep1[-IL,-IR,-S2L <: StandardStep2,-S2R <: StandardStep2,+S2](left:AbstractStep1[IL,S2L],right:AbstractStep1[IR,S2R]) extends AbstractStep1[(IL,IR),S2] {
  def wrapper(l:S2L,r:S2R):S2

  def next_step(i:(IL,IR)):S2 = {
    val (i_left, i_right) = i
    val new_left = left.next_step(i_left)
    val new_right = right.next_step(i_right)
    wrapper(new_left, new_right)
  }
}

class DoubleStandardStep1[-IL,-IR](left:StandardStep1[IL], right:StandardStep1[IR]) extends AbstractDoubleStep1[IL,IR,StandardStep2,StandardStep2,DoubleStandardStep2](left,right) {
  def wrapper(l:StandardStep2,r:StandardStep2) = {
    new DoubleStandardStep2(l,r)
  }
}

class DoubleStandardStep2(left:StandardStep2, right:StandardStep2) extends StandardStep2


class DoubleUniqueStep1[-IL,-IR](left:UniqueStep1[IL], right:UniqueStep1[IR]) extends AbstractDoubleStep1[IL,IR,UniqueStep2,UniqueStep2,DoubleUniqueStep2](left,right) {
  def wrapper(l:UniqueStep2,r:UniqueStep2) = {
    new DoubleUniqueStep2(l,r)
  }
}

class DoubleUniqueStep2(left:UniqueStep2, right:UniqueStep2) extends UniqueStep2

抽象クラスの代わりにトライアットAbstractDoubleStep1に変換することも可能だと思います。これにより、ミックスインの継承がより便利になりますが、現時点ではこれは重要ではありません。

于 2012-10-05T01:29:43.007 に答える