Come faccio a costruire un sistema che abbia tutto quanto segue :
- Utilizzo di funzioni pure con oggetti immutabili.
- Passa in una funzione solo i dati della funzione di cui ha bisogno, non di più (ovvero nessun oggetto di stato di applicazione di grandi dimensioni)
- Evita di avere troppi argomenti per le funzioni.
- Evitare di dover costruire nuovi oggetti solo allo scopo di impacchettare e decomprimere i parametri in funzioni, semplicemente per evitare che troppi parametri vengano passati alle funzioni. Se ho intenzione di impacchettare più elementi in una funzione come un singolo oggetto, voglio che quell'oggetto sia il proprietario di quei dati, non qualcosa di costruito temporaneamente
Mi sembra che la monade di Stato infranga la regola # 2, anche se non è ovvio perché è intrecciata attraverso la monade.
Ho la sensazione che ho bisogno di usare gli obiettivi in qualche modo, ma molto poco è scritto a riguardo per i linguaggi non funzionali.
sfondo
Come esercizio, sto convertendo una delle mie applicazioni esistenti da uno stile orientato agli oggetti a uno stile funzionale. La prima cosa che sto cercando di fare è di rendere il più possibile il nucleo interno dell'applicazione.
Una cosa che ho sentito è che come gestire lo "Stato" in un linguaggio puramente funzionale, e questo è ciò che credo sia fatto dalle monadi statali, è che logicamente, tu chiami una funzione pura ", passando nello stato del mondo com'è ", quindi quando la funzione ritorna, ti restituisce lo stato del mondo come è cambiato.
Per illustrare, il modo in cui puoi fare un "mondo di ciao" in un modo puramente funzionale è un po 'come, passi nel tuo programma quello stato dello schermo e ricevi indietro lo stato dello schermo con "ciao mondo" stampato su di esso. Quindi tecnicamente, stai chiamando una funzione pura e non ci sono effetti collaterali.
Sulla base di ciò, ho esaminato la mia applicazione e: 1. Prima ho messo tutto il mio stato dell'applicazione in un singolo oggetto globale (GameState) 2. In secondo luogo, ho reso GameState immutabile. Non puoi cambiarlo. Se hai bisogno di un cambiamento, devi costruirne uno nuovo. L'ho fatto aggiungendo un costruttore di copia, che opzionalmente prende uno o più campi che sono cambiati. 3. Ad ogni applicazione, passo il GameState come parametro. All'interno della funzione, dopo aver fatto quello che sta per fare, crea un nuovo GameState e lo restituisce.
Come ho un core funzionale puro e un loop all'esterno che alimenta GameState nel loop del flusso di lavoro principale dell'applicazione.
La mia domanda:
Ora, il mio problema è che GameState ha circa 15 diversi oggetti immutabili. Molte delle funzioni al livello più basso operano solo su alcuni di quegli oggetti, come tenere il punteggio. Quindi, diciamo che ho una funzione che calcola il punteggio. Oggi GameState viene passato a questa funzione, che modifica il punteggio creando un nuovo GameState con un nuovo punteggio.
Qualcosa al riguardo sembra sbagliato. La funzione non ha bisogno dell'intero GameState. Ha solo bisogno dell'oggetto Score. Quindi l'ho aggiornato per passare il punteggio e restituire solo il punteggio.
Sembrava avere senso, quindi sono andato oltre con altre funzioni. Alcune funzioni mi richiederebbero di passare 2, 3 o 4 parametri da GameState, ma poiché ho usato il modello fino in fondo al nucleo esterno dell'applicazione, sto passando sempre più lo stato dell'applicazione. Come, all'inizio del ciclo del flusso di lavoro, chiamerei un metodo, che chiamerebbe un metodo che chiamerebbe un metodo, ecc., Fino al punto in cui viene calcolato il punteggio. Ciò significa che il punteggio corrente viene passato attraverso tutti quei livelli solo perché una funzione in fondo calcolerà il punteggio.
Quindi ora ho funzioni con a volte dozzine di parametri. Potrei mettere quei parametri in un oggetto per abbassare il numero di parametri, ma poi vorrei che quella classe fosse la posizione principale dello stato dell'applicazione di stato, piuttosto che un oggetto che è semplicemente costruito al momento della chiamata semplicemente per evitare il passaggio in più parametri, quindi scompattarli.
Quindi ora mi chiedo se il problema che ho è che le mie funzioni sono nidificate troppo profondamente. Questo è il risultato del voler avere piccole funzioni, quindi rifletto quando una funzione diventa grande e la divido in più funzioni più piccole. Ma farlo produce una gerarchia più profonda e tutto ciò che passa alle funzioni interne deve essere passato alla funzione esterna anche se la funzione esterna non opera direttamente su quegli oggetti.
Sembrava semplicemente passare nel GameState lungo la strada per evitare questo problema. Ma sono tornato al problema originale di passare più informazioni a una funzione di quante ne abbia bisogno.