1

申し訳ありませんが、私の問題に関連するタイトルを見つけるのに苦労しています。

次の動作をモデル化したいと考えています。標準の Scala 型をカプセル化する式を使用して「言語」を設計しました。式は、変数または式のシーケンスのいずれかです。以下では、A は標準の Scala 型 (つまり、Boolean、Int、Double) にすることができます。また、式 (特にシーケンス) で式を他のものに置き換える方法を実装したいと考えています。コンパイルできないコードをいくつか試しました。どのタイプを入れればよいかわからないときに引用符を付けましたが、これはおそらく面倒です。再帰的な性質のために、私はシーケンスのことで特別な問題を抱えています。

sealed trait Expression[A] {
  def replace[B](a: Expression[B], b: Expression[B]): Expression[?]
}

trait Variable[A] extends Expression[A] {
  def replace[B](a: Expression[B], b: Expression[B]) = 
    if (a == this) b else this
}

case class Sequence[A <: Expression[B]](values: Seq[A]) extends Expression[A] {
   def replace[B](a: Expression[B], b: Expression[B]) = 
     if (a == this) b
     else Sequence(values.map(_.replace(a, b)))
}

もちろん、無限再帰をトリガーするため、シーケンスは非循環的 (シーケンスはそれ自体を含むことはできません) であると想定しています。これらは、n-ary 行列を実装するために使用されます。

ご協力いただきありがとうございます。

4

3 に答える 3

3

Scala がエレガントなソリューションを持たないコーナーケースの 1 つに遭遇したようです。

戻り型としての代わりに必要なのは、Expression[?]実際には「この型」を表す型であり、特性が実際に混在する型です。これを簡単な方法で表現できる速記は Scala にはありません。this.typeどちらも使用できませんthis

解決策は通常、驚くべきボイラープレートをすぐに導入します。たとえば、Scala コレクションには同じ問題があり、MapLike同様のものをエンコードする必要があるなどの特性があります。

このような型をエンコードするために、サンプルをすばやく変更しようとしました。コンパイルできることを確認しましたが、実行しませんでした:

sealed trait Expression[A, ThisType <: Expression[A, ThisType]] {
  def replace[B,C <: Expression[B,C]](a: Expression[B,C], b: Expression[B,C]): ThisType
}

trait Variable[A] extends Expression[A, Variable[A]] {
  def replace[B,C <: Expression[B,C]](a: Expression[B,C], b: Expression[B,C]) = 
    if (a == this) b.asInstanceOf[Variable[A]] else this
}

case class Sequence[A <: Expression[_,A]](values: Seq[A]) extends Expression[A, Sequence[A]] {
   def replace[B,C <: Expression[B,C]](a: Expression[B,C], b: Expression[B,C]) = 
     if (a == this) b.asInstanceOf[Sequence[A]]
     else Sequence(values.map(_.replace(a, b)))
}

通常はそれ自体が臭いですが、キャストを使用する必要さえありますが、この場合、それを回避する方法があるかどうかはわかりません. 少なくとも安全です。正しい型でなければならないことはわかっていますが、コンパイラがそれを認識していないだけです。:-)

于 2014-02-19T23:11:11.507 に答える