Action
Per la modellazione della tipologia di azioni che è possibile svolgere dalle entità dinamiche è stato adottato un approccio basato sul pattern Tagless Final, che consente di definire in maniera astratta e componibile i comportamenti applicabili a un’entità senza vincolarsi a una specifica implementazione.
Tagless final pattern
Il pattern tagless final consente di separare la definizione di un’azione dalla sua esecuzione concreta. In particolare:
- l'interfaccia astratta
Action[F[_]]descrive le operazioni disponibili e i comportamenti possibili, parametrizzandoli sul tipo di effettoF[_]; - l'algebra concreta
ActionAlg[F, E]specifica come tali operazioni vengono effettivamente eseguite su una determinata entitàE.
Questo approccio favorisce la flessibilità e la riusabilità, consentendo di definire nuove azioni o contesti di esecuzione senza modificare il modello di base delle entità dinamiche.
Di seguito viene riportata la definizione di Action:
trait Action[F[_]]:
def run[E <: DynamicEntity](e: E)(using a: ActionAlg[F, E]): F[E]
L’esecuzione dell’azione è demandata a un’interfaccia separata,
ActionAlg[F, E], che definisce l’algebra delle operazioni disponibili su un’entità dinamica E che deve
estendere DynamicEntity.
In questo modo si realizza una netta distinzione tra cosa può essere fatto (la definizione dell’azione) e come viene
fatto.
Al momento, ActionAlg definisce un singolo metodo moveWheels.
trait ActionAlg[F[_], E <: DynamicEntity]:
def moveWheels(e: E, leftSpeed: Double, rightSpeed: Double): F[E]
Questo consente di applicare velocità diverse alle ruote dell’entità dinamica, permettendo così di controllarne il movimento.
Nota: in futuro, questa interfaccia potrà essere estesa per includere ulteriori tipologie di azioni.
Sono state poi definite diverse implementazioni di Action:
MovementAction: che rappresenta un movimento applicando velocità diverse alle ruote;NoAction: che lascia inalterata l’entità;SequenceAction: che permette di comporre più azioni in sequenza, garantendo un’esecuzione ordinata e monadica.
A supporto è stato introdotto anche l’oggetto MovementActionFactory, che fornisce un insieme di azioni predefinite
(avanti, indietro, svolta a sinistra/destra, stop) e un metodo per la creazione di movimenti personalizzati con
validazione sui parametri di velocità.
Implementazione di ActionAlg per Robot
Nel companion object Robot viene inoltre fornita l’implementazione di ActionAlg[IO, Robot], ovvero
l’interprete dell’algebra delle azioni in un contesto di effetto IO.
In particolare, l’implementazione del metodo moveWheels aggiorna lo stato degli attuatori di tipo
DifferentialWheelMotor, applicando nuove velocità alle ruote sinistra e destra, e restituendo un nuovo stato del
robot incapsulato in IO.
Grazie a questa architettura e all’uso del pattern Tagless Final (introdotto nella modellazione delle azioni), il robot può eseguire azioni in modo astratto e indipendente dal contesto, garantendo modularità ed estensibilità.