Qual é o atual padrão recomendado para o polimorfismo familiar em Scala?
Ao experimentar maneiras de modelar jogos, essa solução surgiu recentemente:
trait Game[G <: Game[G]] {
type PLAYER <: Player[G]
type STATE <: State[G]
def players(): Set[G#PLAYER]
def startState(): G#STATE
}
trait Player[G <: Game[G]]
trait State[G <: Game[G]] {
def player(): G#PLAYER
}
Um jogo específico (poker neste exemplo) pode ser expresso em termos de características como:
class Poker() extends Game[Poker] {
type PLAYER = PokerPlayer
type STATE = PokerState
val p1 = new PokerPlayer()
def players() = Set(p1)
def startState(): PokerState = ...
}
class PokerPlayer() extends Player[Poker]
class PokerState() extends State[Poker] {
def player(): PokerPlayer = ...
}
Eu tenho várias perguntas sobre essa configuração:
Como é
Game[G <: Game[G]]
pronunciado em inglês? Quais são os nomes das funções queG
eGame
está jogando nesta situação? (Significado especificamente nesse relacionamento "recursivo".)Esta é uma implementação razoável de "famíliapolimorfismo "? Em um nível alto, meu entendimento é que isso significa que o Jogo e seu JOGADOR e ESTADO devem variar como uma" família ". As opiniões sobre o polimorfismo familiar em Scala, que eu já vi em outros lugares, diferem substancialmente, e não estou claro sobre as diferentes vantagens e desvantagens:
Visão geral de Scala (2006) http://www.scala-lang.org/docu/files/ScalaOverview.pdf
Blog de Martin Kneissl (2009) http://www.familie-kneissl.org/Members/martin/blog/family-polymorphism-in-scala
Discussões sobre abordagens do polimorfismo familiar envolvendo classes de tipos, macros, polimorfismo limitado a f ou qualquer outra coisa são bem-vindas.
Respostas:
2 para resposta № 1Eu questionaria a necessidade de definir as classes "fora" da característica. Os tipos Player
e State
já dependem do jogo, então você não precisa restringi-lo ainda mais.
trait Game {
type Player
type State <: StateLike
trait StateLike {
def player: Player
}
def startState: State
}
class Poker extends Game {
class Player
class State extends StateLike { ... }
val startState = new State
}
Você pode usar o padrão de bolo para separar partes diferentes em diferentes características / arquivos, se desejar.
trait PokerPlayer extends Game {
class Player
}
trait PokerState extends Game with PokerPlayer {
class State extends StateLike { ... }
}
class Poker extends Game with PokerPlayer with PokerState {
val startState = ...
}