Scala 型システムを理解していないようです。私は、2 つの基本的な特性と、アルゴリズムのファミリーがそれらと連携するための特性を実装しようとしています。以下で何が間違っていますか?
動きと状態の基本特性。これらは、問題を明らかにするメソッドを含めるように単純化されています。
trait Move
trait State[M <: Move] {
def moves: List[M]
def successor(m: M): State[M]
}
上記を利用するアルゴリズムのファミリーの特性は次のとおりです。私はこれが正しいかどうかわからない!+M / -S が関係している可能性があります...
trait Algorithm {
def bestMove[M <: Move, S <: State[M]](s: S): M
}
具体的な動きと状態:
case class MyMove(x: Int) extends Move
class MyState(val s: Map[MyMove,Int]) extends State[MyMove] {
def moves = MyMove(1) :: MyMove(2) :: Nil
def successor(p: MyMove) = new MyState(s.updated(p, 1))
}
私は以下に関して非常に不安定な立場にありますが、コンパイラはそれを受け入れているようです... Algorithm トレイトの具体的な実装を試みています。
object MyAlgorithm extends Algorithm {
def bestMove(s: State[Move]) = s.moves.head
}
これまでのところ、コンパイル エラーはありません。ただし、すべてのパーツをまとめようとすると表示されます。
object Main extends App {
val s = new MyState(Map())
val m = MyAlgorithm.bestMove(s)
println(m)
}
上記はこのエラーをスローします:
error: overloaded method value bestMove with alternatives:
(s: State[Move])Move <and>
[M <: Move, S <: State[M]](s: S)M
cannot be applied to (MyState)
val m = MyAlgorithm.bestMove(s)
^
更新:提案されているように、抽象型メンバーを使用するように Algorithm 特性を変更しました。これは、私が言い表したように質問を解決しましたが、少し単純化しすぎました。MyAlgorithm.bestMove()
メソッドは、次のように、s.successor(m) からの出力で自分自身を呼び出すことができる必要があります。
trait Algorithm {
type M <: Move
type S <: State[M]
def bestMove(s: S): M
}
trait MyAlgorithm extends Algorithm {
def score(s: S): Int = s.moves.size
def bestMove(s: S): M = {
val groups = s.moves.groupBy(m => score(s.successor(m)))
val max = groups.keys.max
groups(max).head
}
}
上記により、2 つのエラーが発生します。
Foo.scala:38: error: type mismatch;
found : State[MyAlgorithm.this.M]
required: MyAlgorithm.this.S
val groups = s.moves.groupBy(m => score(s.successor(m)))
^
Foo.scala:39: error: diverging implicit expansion for type Ordering[B]
starting with method Tuple9 in object Ordering
val max = groups.keys.max
^
これを機能させるには、トレイトのトレイト (ケーキ パターンとも呼ばれる) を使用するアプローチに移行する必要がありますか? (私はここで推測しているだけです。私はまだ完全に混乱しています。)