Domanda

Ho bisogno di aiuto per aggirare la differenza tra la mia attuale nozione di stato OOP e il modo in cui verrebbe fatto in un linguaggio funzionale come Haskell o Clojure.

Per usare un esempio falso, supponiamo di avere a che fare con oggetti / strutture / qualunque conto del conto bancario semplificati. In un linguaggio OOP, avrei una classe in possesso di un riferimento a un BankAccount, che avrebbe variabili di istanza per cose come il tasso di interesse e metodi come setInterestRate () che cambiano lo stato dell'oggetto e generalmente non restituiscono nulla. In Clojure, direi che avrei una struttura di conto bancario (una hashmap glorificata) e funzioni speciali che accettano un parametro di conto bancario e altre informazioni e restituiscono una nuova struttura. Quindi, invece di cambiare lo stato dell'oggetto originale, ora ne ho uno nuovo restituito con le modifiche desiderate.

Quindi ... cosa ci faccio? Sovrascrivi quale variabile faceva riferimento al vecchio conto bancario? In tal caso, ciò presenta vantaggi rispetto all'approccio OOP che cambia stato? Alla fine, in entrambi i casi sembra che si abbia una variabile che fa riferimento all'oggetto con le modifiche necessarie. Ritardato come sono, ho solo un vago concetto di ciò che sta succedendo.

Spero che abbia senso, grazie per l'aiuto!

È stato utile?

Soluzione

In puro stile funzionale, non sovrascriverai mai alcuna variabile.

Un'analogia sarebbe con lo spaziotempo in fisica. Se consideri il mondo come 3d, gli oggetti non hanno posizioni fisse, ma si muovono nel tempo. Per fare in modo che la matematica si basi sul mondo fisico, aggiungiamo quindi una dimensione temporale e consideriamo i valori di varie proprietà in momenti particolari. Nel fare ciò, abbiamo trasformato gli oggetti del nostro studio in costanti. Allo stesso modo, nella programmazione, c'è una semplicità concettuale da avere lavorando con valori immutabili. Gli oggetti con un'identità nel mondo reale possono essere modellati come una sequenza di valori immutabili (gli stati dell'oggetto in tempi crescenti) piuttosto che come un singolo valore che cambia.

Ovviamente i dettagli su come associare la sequenza di valori a un " identità dell'oggetto " può essere un po 'peloso. Haskell ha Monadi che ti permettono di modellare lo stato. Programmazione reattiva funzionale è un tentativo più letterale di modellare oggetti nel mondo con puri aggiornamenti funzionali, che io penso che sia una direzione molto promettente per la programmazione.

Noterò che Clojure, a differenza di Haskell, non è puro e puoi aggiornare le variabili come hai suggerito. Se stai aggiornando solo alcune variabili ad alto livello, probabilmente ti godrai comunque molti dei vantaggi concettuali della semplicità della programmazione funzionale.

Altri suggerimenti

Presumibilmente nel mondo OO hai un ciclo e stai modificando questi conti bancari più e più volte in risposta alle richieste. Supponiamo che tu abbia un intero portafoglio di conti e questi abbiano tipo Portfolio. Quindi in Haskell dovresti scrivere una funzione pura

updatePortfolio :: Request -> Portfolio -> Portfolio

E il tuo ciclo principale potrebbe leggere le richieste dallo standard input e mantenere aggiornato il tuo portafoglio. (L'esempio non è molto utile a meno che non sia possibile scrivere anche il portfolio, ma è più semplice.)

readRequest :: IO Request  -- an action that, when performed, reads a Request with side effects

main :: Portfolio -> IO ()  -- a completely useless program that updates a Portfolio in response to a stream of Requests

main portfolio = do req <- readRequest
                    main (updatePortfolio req)

e ora spero che tu veda cosa è successo al tuo stato mutevole: in un tipico programma funzionale, dichiari che le modifiche vengono passate come parametro a una funzione. Quando lo stato cambia, si effettua una nuova chiamata di funzione. La chiamata è in posizione di coda (puoi cercare 'chiamata di coda corretta') e quindi non usa alcuna risorsa aggiuntiva, e infatti quando il compilatore genera un codice assembly genera un ciclo e manterrà il puntatore al Portfolio in continua evoluzione in un registro.

Questo è un esempio molto giocattolo, ma spero che ti dia un po 'il sapore di un linguaggio funzionale.

Quindi ... cosa ci faccio? Sovrascrivi la variabile che faceva riferimento al vecchio conto bancario?

Si

In tal caso, ciò presenta vantaggi rispetto all'approccio OOP che cambia lo stato?

Diciamo che il calcolo di qualsiasi azione tu faccia su quella struttura richiede molto tempo e qualcosa accade a metà strada e devi tornare alla struttura originale o il calcolo ha generato un errore. Con l'interpretazione che mi hai presentato di OO (usando un riferimento, perché puoi avere un linguaggio OO immutabile) che i dati potrebbero essere corrotti - sono sconosciuti a meno che non siano state fornite abbastanza informazioni dalla chiamata di funzione fallita e lasciamo supporre che non sia riuscito male. In un approccio funzionale sai con certezza che la tua struttura di dati originale è corretta, perché inizialmente ne hai fatto una copia.

Estendi questo scenario in applicazioni multi-thread. Siamo in grado di garantire che nessun altro stia utilizzando la struttura di dati che siamo poiché tutti ne abbiamo la nostra versione.

Inoltre, possiamo risparmiare spazio utilizzando i dati dell'altra struttura da cui stiamo copiando. Un esempio classico è quando si aggiunge un elemento all'inizio di un elenco. Se abbiamo un puntatore al secondo elemento e un puntatore al primo elemento possiamo fare riferimento a entrambi gli elenchi con solo la dimensione del primo (vedi sotto). Senza immutabilità non possiamo garantirlo.

        b__
           |  
a -> [6|] -+-> [5|] -> [4|] -> [3|] -> [2|] -> [1|x]

Guarda Haskell, che è un linguaggio funzionale puro & # 8212; non ha alcuna riassegnazione di sorta, così come nessun altro effetto collaterale: per fare IO, nel IO monade sostituisce effettivamente il RealWorld con una nuova istanza del mondo che ha, ad esempio, nuovo testo visualizzato nella console.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top