Diciamo che scrivere il codice seguente:Haskell - risolvere modulo ciclico dipendenza
un gioco Modulo
module Game where
import Player
import Card
data Game = Game {p1 :: Player,
p2 :: Player,
isP1sTurn :: Bool
turnsLeft :: Int
}
un giocatore
module Player where
import Card
data Player = Player {score :: Int,
hand :: [Card],
deck :: [Card]
}
e un modulo di carta
module Card where
data Card = Card {name :: String, scoreValue :: Int}
Poi scrivo del merluzzo e per implementare la logica in cui i giocatori a turno disegnano e giocano a carte dalla propria mano per aggiungere bonus al proprio punteggio fino a quando il gioco finisce i turni.
Tuttavia, mi rendo conto al termine di questo codice che il modulo di gioco che ho scritto è noioso!
Voglio refactoring del gioco di carte in modo che quando si gioca una carta, piuttosto che solo aggiungendo un punteggio, invece la carta trasforma arbitrariamente il gioco.
Quindi, posso cambiare il modulo Card
al seguente
module Card where
import Game
data Card = Card {name :: String,
onPlayFunction :: (Game -> Game)
scoreValue :: Int}
che ovviamente rende le importazioni dei moduli formano un ciclo.
Come posso risolvere questo problema?
Trivial Soluzione:
spostare tutti i file allo stesso modulo. Questo risolve bene il problema, ma riduce la modularità; Non posso più riutilizzare lo stesso modulo per un'altra partita.
Modulo soluzione mantenimento:
Aggiungere un parametro di tipo a Card
:
module Card where
data Card a = {name :: String, onPlayFunc :: (a -> a), scoreValue :: Int}
Aggiungere un altro parametro per Player
:
module Player where
data Player a {score :: Int, hand :: [card a], deck :: [card a]}
Con una modifica finale Game
:
module Game where
data Game = Game {p1 :: Player Game,
p2 :: Player Game,
}
Ciò mantiene la modularità, ma richiede l'aggiunta di parametri ai miei tipi di dati. Se le strutture dei dati fossero più profondamente annidate, potrei aggiungere un sacco di parametri ai miei dati e, se dovessi usare questo metodo per più soluzioni, potrei finire con un numero ingombrante di modificatori di tipi.
Quindi, ci sono altre soluzioni utili per risolvere questo refactoring, o sono queste le uniche due opzioni?
Preferisco fortemente raccomandare di evitare il meccanismo '{- # SOURCE # -}'/.hs-boot, a meno che non sia veramente necessario. – leftaroundabout
@leftroundabout: Sì, lo trovo laborioso e scomodo, ma ci sono argomenti contro di esso diversi da quelli menzionati nel [wiki] (https://wiki.haskell.org/Mutually_recursive_modules), che sono (imho) non così rilevante per i piccoli progetti? –