Come faccio a costruire un sistema che ha tutti i seguenti :
- Uso di funzioni pure con oggetti immutabili
- Passa solo in una funzione dati che la funzione di cui ha bisogno, non più (cioè nessun grande oggetto stato dell'applicazione)
- 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 impaccherò più oggetti in una funzione come un singolo oggetto, voglio che quell'oggetto sia il proprietario di quei dati, non qualcosa costruito temporaneamente
Mi sembra che la monade di Stato infrange la regola n. 2, sebbene non sia ovvia perché è intrecciata attraverso la monade.
Ho la sensazione che ho bisogno di usare gli obiettivi in qualche modo, ma ne ho scritto pochissimo 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 è rendere il più possibile l'inner-core dell'applicazione.
Una cosa che ho sentito è che come gestire lo "stato" in un linguaggio puramente funzionale, e questo è quello che credo sia fatto dalle monadi di stato, è che logicamente, si chiama una funzione pura, "passando nel stato del mondo così com'è ", quindi quando la funzione ritorna, restituisce a te lo stato del mondo come è cambiato.
Per illustrare, il modo in cui si può fare un "ciao mondo" in modo puramente funzionale è un po 'come, si passa al programma lo stato dello schermo e si riceve lo stato dello schermo con "Ciao mondo" stampato su di esso. Quindi, tecnicamente, stai facendo una chiamata a una funzione pura, e non ci sono effetti collaterali.
In base a ciò, ho esaminato la mia domanda e: 1. In primo luogo, metti tutti i miei stati di 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. Ho fatto questo aggiungendo un costruttore di copia, che opzionalmente accetta uno o più campi che sono cambiati. 3. Per ogni applicazione, passo in 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 quel GameState nel loop del flusso di lavoro principale dell'applicazione.
La mia domanda:
Ora, il mio problema è che, il GameState ha circa 15 diversi oggetti immutabili. Molte delle funzioni al livello più basso operano solo su pochi di questi oggetti, come il mantenimento del punteggio. Quindi, diciamo che ho una funzione che calcola il punteggio. Oggi, il GameState è passato a questa funzione, che modifica il punteggio creando nuovo GameState con un nuovo punteggio.
Qualcosa a riguardo sembra sbagliato. La funzione non ha bisogno della totalità di GameState. Ha solo bisogno dell'oggetto Punteggio. Quindi l'ho aggiornato per passare il punteggio e restituire solo il punteggio.
Sembrava aver senso, quindi sono andato oltre con altre funzioni. Alcune funzioni mi richiederebbero di passare in 2, 3 o 4 parametri dal GameState, ma dal momento che ho usato il pattern fino in fondo al nucleo esterno dell'applicazione, sto passando in sempre più dello stato dell'applicazione. Ad esempio, 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 lungo tutti questi livelli solo perché una funzione in fondo sta per calcolare il punteggio.
Quindi ora ho delle funzioni con qualche dozzina 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 stato, piuttosto che un oggetto che è semplicemente costruito al momento della chiamata semplicemente per evitare di passare in più parametri, quindi decomprimili.
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 mi rifatto quando una funzione diventa grande e la diviso in più funzioni più piccole. Ma fare ciò produce una gerarchia più profonda, e tutto ciò che è passato nelle funzioni interne deve essere passato alla funzione esterna anche se la funzione esterna non sta operando direttamente su quegli oggetti.
Sembrava semplicemente passare il GameState lungo la strada per evitare questo problema. Ma sono tornato al problema originale di passare più informazioni a una funzione di quante la funzione abbia bisogno.