Mutabilità e oggetti; come gestire correttamente i dati?

5

Gli oggetti tendono a confondermi. Comprendere il concetto e l'uso, certamente, ma mi sembra che il paradigma funzionale stia limitando in qualche modo il mio uso di essi.

Al momento sto creando un codice semplice per un gioco di carte. Ogni giocatore potrebbe avere un oggetto semplice, come questo:

object player {
    name = "Steve";
    score = 0;
    hand = [/*...contains seven cards...*/];
}

e un oggetto per un mazzo:

object deck {
    cards = [/*...contains the other 45 cards...*/]
}

Quindi per distribuire nuove carte, il modo più semplice sarebbe quello di mutare la this.hand e la this.cards. Ma ... mutazione.

Posso pensare ad altri modi per farlo, ma i modi puramente funzionali che riesco a pensare mi fanno incazzare.

A che punto si traccia la linea tra dati mutevoli e immutabili o cosa mi manca?

    
posta Ucenna 04.12.2016 - 21:47
fonte

3 risposte

1

È piuttosto semplice: se vuoi percorrere la "strada funzionale pura", hai bisogno di strutture di dati puramente funzionali , che significa strutture di dati immutabili, che nelle lingue OO significa oggetti immutabili.

Per rappresentare i mazzi di carte, una struttura molto efficiente e immutabile è una pila, implementata come una singola lista collegata (e non come una matrice!), forse combinata con un contatore di dimensioni. Quindi le tipiche operazioni di stack come aggiungere una carta in cima, rimuovendone una dalla cima, possono essere implementate come operazioni immutabili in O (1). L'iterazione diretta di tutti gli elementi può essere implementata in O (N). L'accesso casuale a una determinata carta diventerà un'operazione O (N) (invece di O (1) quando si utilizza un'implementazione dell'array), ma le operazioni più significative con le carte possono essere implementate senza quest'ultimo, o non ha un impatto grave sul tempo di esecuzione per la maggior parte dei casi pratici.

the purely functional ways I can think of feel messy

Non mi sento così - l'uso di un'astrazione di stack non è necessariamente più o meno "disordinato" rispetto all'utilizzo di un'astrazione di array. L'unico ostacolo che vedo è che le librerie standard dei linguaggi OO del flusso principale come C ++, C # o Java non forniscono implementazioni standard per qualcosa di simile a uno stack immutabile "out of the box". La maggior parte delle lingue funzionali probabilmente lo fa oggi. Basta google per immutable stack <your favourite language> o immutable object tutorial <language> e troverai probabilmente quello che ti serve.

Tuttavia, se sei più abituato alla classica modellazione OO con lo stato mutabile, puoi modellare e implementare il tuo gioco di carte usando classi mutevoli (ma poi non sarà più funzionale).

    
risposta data 05.12.2016 - 13:54
fonte
1

Nella mutazione FP di un'entità viene modellata come una creazione del suo stato successivo. Primo, l'entità ha uno stato rappresentato da un oggetto complesso arbitrario, nel momento successivo può avere un altro. Questi stati includono stati per tutte le proprietà dell'entità, ad esempio, lo stato del giocatore può includere lo stato della sua mano, lo stato del mondo include lo stato dei giocatori e lo stato del mazzo.

Una semplice mutazione, che coinvolge solo un aspetto dello stato, viene raggiunta dalla copia superficiale dello stato precedente, sostituendo uno dei suoi valori di proprietà.

I linguaggi funzionali (dovrebbero) hanno una sintassi o librerie designate per tale trasformazione.

Semplice mutazione senza l'uso di librerie specifiche e nella sintassi Javascript:

function score (world) {
   return {
     deck: world.deck,
     player: {
        name: world.player.name,
        score: world.player.score + 1,
        hand: world.player.hand
    }
}

Con miglioramenti della sintassi:

function score (world) {  world { player.score = world.player.score + 1 }; }

Esempio ipotetico con logica non banale, che rappresenta meglio le transizioni dello stato reale:

function win (world) {
  return {
     deck: world.deck.merge (world.player.hand),
     player: {name: world.player.name, score: world.player.score + 1, hand:[] }
}
    
risposta data 05.12.2016 - 19:38
fonte
-3

OO e programmazione funzionale sono concetti ortogonali. Quindi se li mescoli in modo improprio non otterrai il meglio di entrambi, ma il peggio di entrambi.

Mutare strutture con funzioni è il peggiore che puoi fare. Hai effetti collaterali E non sai chi è il responsabile della coerenza della struttura.

O incapsulate la mutazione in un oggetto e lasciate che l'oggetto preservi la coerenza O usate strutture di dati immutabili e rappresentate qualsiasi nuovo stato con una nuova struttura di dati. Se segui questo, puoi mescolare i paradigmi senza inconvenienti.

    
risposta data 05.12.2016 - 20:36
fonte

Leggi altre domande sui tag