2010-06-13 7 views
4

j'ai essayé de créer abstrait jeu tour par tour et abstraite AI:erreur Scala étrange

abstract class AGame { 
    type Player 
    type Move  // Player inside 

    def actPlayer : Player 
    def moves (player : Player) : Iterator[Move] 
    def play (move : Move) 
    def undo() 
    def isFinished : Boolean 
    def result (player : Player) : Double 
} 

abstract class Ai[Game <: AGame] { 
    def genMove (player : Game#Player) : Game#Move 
} 

class DummyGame extends AGame { 
    type Player = Unit 
    type Move = Unit 

    def moves (player : Player) = new Iterator[Move] { 
    def hasNext = false 
    def next = throw new Exception ("asd") 
    } 

    def actPlayer =() 

    def play (move : Move) { 
    } 

    def undo() { 
    } 

    def isFinished = true 

    def result (player : Player) = 0 
} 

class DummyAi[Game <: AGame] (game : Game) extends Ai[Game] { 
    override def genMove (player : Game#Player) : Game#Move = { 
    game.moves (player).next 
    } 
} 

Je pensais que je dois utiliser ce type étrange accesseurs comme jeu # joueur. Je reçois une erreur très embarrassante. Je voudrais comprendre:

[error] /home/lew/Devel/CGSearch/src/main/scala/Main.scala:41: type mismatch; 
[error] found : Game#Player 
[error] required: DummyAi.this.game.Player 
[error]  game.moves (player).next 
[error]    ^
+0

Est-ce supposé être 'game.moves (player) .next' ou' game.moves (player.next) '? La syntaxe Scala est ambiguë pour permettre les deux interprétations, mais l'analyseur devrait en choisir une. – Theo

+0

Du message d'erreur, il semble clair qu'il est analysé comme le premier. –

Répondre

5

def moves (player : Player) signifie que moves accepte un joueur pour cette Game.

Game#Player est le type pour un joueur de unGame. Donc, moves (player) est une incompatibilité de type.

Voici un exemple simple qui montre pourquoi doit être être une discordance. Supposons que ce n'était pas et voir ce qui se passe à côté:

class Game2 extends DummyGame { 
    override type Player = Boolean 
    override type Move = Boolean 

    override def moves(player : Boolean) = new Iterator[Boolean] {...} 
} 

val game2: DummyGame = new Game2 
// game2.Player is Boolean 

val dummyGameAi = new DummyAi[DummyGame](game2) 
// DummyGame#Player == Unit, so the type of genMove for Ai[DummyGame] is 
// def genMove (player : Unit) : Unit 

dummyGameAi.genMove(()) 
// this calls game2.moves(()), which doesn't typecheck 

Pour que cela fonctionne, nous pouvons changer le type de genMove. Si nous passons un jeu comme un argument (et il est logique de toute façon), nous pouvons utiliser la route en fonction des types:

abstract class Ai[Game <: AGame] { 
    def genMove (game : Game)(player : game.Player) : game.Move 
    // now game.moves (player) typechecks 
} 
+0

Je comprends mais je ne vois toujours pas comment je devrais résoudre ce problème. Toutes les idées –

+0

ne provoquera-t-elle pas une erreur de type de méthode dépendante illégale? – BenjaminJackman

+0

Avez-vous utilisé l'option '-Xexperimental'? http://lampsvn.epfl.ch/trac/scala/ticket/128 –

3

Vous pouvez résoudre votre problème en introduisant un membre abstrait game dans Ai puis spécifiez le chemin dépendant type utilisant ce membre:

abstract class Ai[Game <: AGame] { 
    val game : Game 
    def genMove (player : game.Player) : game.Move 
} 

class DummyAi[Game <: AGame] (val game : Game) extends Ai[Game] { 
    override def genMove (player : game.Player) : game.Move = { 
    game.moves (player).next 
    } 
}