以下に示すように、多かれ少なかれオブジェクトインスタンスをモジュール/ファンクターとして使用したい:
abstract class Lattice[E] extends Set[E] {
val minimum: E
val maximum: E
def meet(x: E, y: E): E
def join(x: E, y: E): E
def neg(x: E): E
}
class Calculus[E](val lat: Lattice[E]) {
abstract class Expr
case class Var(name: String) extends Expr {...}
case class Val(value: E) extends Expr {...}
case class Neg(e1: Expr) extends Expr {...}
case class Cnj(e1: Expr, e2: Expr) extends Expr {...}
case class Dsj(e1: Expr, e2: Expr) extends Expr {...}
}
格子ごとに異なる微積分インスタンスを作成できるようにします (実行する操作には、格子の最大値と最小値の情報が必要です)。同じ微積分の式を混合できるようにしたいが、異なる式を混合することは許可されていません。ここまでは順調ですね。微積分インスタンスを作成できますが、問題は、それらを操作する他のクラスに関数を記述できないことです。
たとえば、ファイルから式を読み取って返すパーサーを作成しようとしています。また、ScalaCheck を使用したテストで使用するランダム式ジェネレーターを作成しようとしていました。関数が Expr オブジェクトを生成するたびに、関数の外では使用できないことがわかりました。Calculus インスタンスを作成し、Expr オブジェクトを生成する関数に引数として渡しても、関数の戻り値は、関数の外部で作成されたオブジェクトと同じ型として認識されません。
多分私の英語は十分に明確ではありません.私がやりたいことのおもちゃの例を試してみましょう.
def genRndExpr[E](c: Calculus[E], level: Int): Calculus[E]#Expr = {
if (level > MAX_LEVEL) {
val select = util.Random.nextInt(2)
select match {
case 0 => genRndVar(c)
case 1 => genRndVal(c)
}
}
else {
val select = util.Random.nextInt(3)
select match {
case 0 => new c.Neg(genRndExpr(c, level+1))
case 1 => new c.Dsj(genRndExpr(c, level+1), genRndExpr(c, level+1))
case 2 => new c.Cnj(genRndExpr(c, level+1), genRndExpr(c, level+1))
}
}
}
さて、上記のコードをコンパイルしようとすると、たくさんの
エラー: タイプが一致しません。 見つかった : plg.mvfml.Calculus[E]#Expr 必須: c.Expr ケース 0 => 新しい c.Neg(genRndExpr(c、レベル + 1))
次のようなことをしようとすると、同じことが起こります。
val boolCalc = new Calculus(Bool)
val e1: boolCalc.Expr = genRndExpr(boolCalc)
ジェネレーター自体は問題ではありませんが、システムの残りの部分で同様のこと (つまり、微積分インスタンス式の作成と操作) を行う必要があることに注意してください。
私は何か間違ったことをしていますか?私がやりたいことをすることは可能ですか?
この問題に関するヘルプは非常に必要であり、高く評価されています. よろしくお願いします。
Apocalisp から回答を受け取り、試した後。
回答ありがとうございます。ただし、まだいくつかの問題があります。提案された解決策は、関数の署名を次のように変更することでした。
def genRndExpr[E, C <: Calculus[E]](c: C, level: Int): C#Expr
関連するすべての関数 (getRndExpr、getRndVal、および getRndVar) の署名を変更しました。そして、これらの関数を呼び出すすべての場所で同じエラー メッセージが表示され、次のエラー メッセージが表示されました。
エラー: 推論された型引数 [Nothing,C] はメソッド genRndVar に準拠していません 型パラメータ境界 [E,C <: plg.mvfml.Calculus[E]] ケース 0 => genRndVar(c)
コンパイラが正しい型を判断できないように見えたので、すべての関数呼び出しを次のように変更しました。
case 0 => new c.Neg(genRndExpr[E,C](c, level+1))
この後、最初の 2 回の関数呼び出し (genRndVal と genRndVar) ではコンパイル エラーは発生しませんでしたが、次の 3 回の呼び出し (genRndExpr への再帰呼び出し) では、関数の戻り値を使用して新しい Expr オブジェクトを作成します。次のエラー:
エラー: タイプが一致しません。 見つかった: C#Expr 必須: c.Expr ケース 0 => 新しい c.Neg(genRndExpr[E,C](c, level+1))
だから、また行き詰まった。どんな助けでも大歓迎です。