Getter e setter in linguaggi funzionali


9

Uno dei principi della programmazione funzionale è l'uso delle funzioni pure. Una funzione Pure è libera da effetti collaterali e trasparente dal punto di vista referenziale.

I getter non sono referenzialmente trasparenti: se viene chiamato un Setter tra le chiamate al Getter, il valore di ritorno del Getter cambia anche se i suoi parametri non hanno (in genere nessun parametro)

I setter producono effetti collaterali - Chiamare un setter in genere manipola un valore che non è il suo valore di ritorno (in effetti, tradizionalmente un setter non restituisce nulla)

So che in Scala accettiamo semplicemente il fatto che stiamo mettendo insieme due paradigmi (funzionali e orientati agli oggetti) e usiamo getter / setter come faremmo in un linguaggio come Java.

In un linguaggio come Haskell (di cui non parlo fluentemente, ma mi viene detto che è più vero per un linguaggio funzionale "Puro") Sono solo curioso di sapere come modellereste le proprietà su oggetti in modo tale che Getter sia trasparente dal punto di vista referenziale e Setter sono privi di effetti collaterali?

La soluzione sarebbe quella di restituire una copia dell'oggetto su cui è stato invocato il setter come valore di ritorno del setter e questa copia contiene la modifica al valore della proprietà?


8
Getter e setter hanno l'oggetto come parametro - anche se di solito è implicito - quindi i getter sono trasparenti dal punto di vista referenziale.

@delnan, solo se l'attributo che sta leggendo è immutabile.
dan_waterworth,

3
@dan_waterworth: solo se leggiamo lo "stesso" in "referenzialmente trasparente" come identità dell'oggetto. Se il fatto che l'attributo sottostante è diverso lo rende una chiamata con argomenti diversi (che è in linea con la maggior parte delle definizioni di uguaglianza). Questo sta ignorando un altro thread che chiama un setter e lo termina tra la chiamata al getter e il getter di finitura, ma in quel caso hai comunque problemi più seri.

Risposte:


7

Esattamente. Vedi il metodo della classe di custodia copyo il concetto generale di obiettivi.

In particolare, se lo stato ha bisogno di essere cambiato, useresti una monade statale. Le modifiche a quella monade dello stato possono essere apportate attraverso obiettivi, il che rende facile estrarre informazioni dallo "stato" e modificarlo.

Vedi anche questa domanda sul problema generale che deriva da una struttura profonda come lo "stato" e la modifica. Le risposte hanno buoni collegamenti su entrambe le lenti e le cerniere se vuoi approfondire.


Domanda Daniel: c'è qualche motivo particolare per cui copy () è legato alle classi Case? Questo non sembra specifico per le esigenze (parola sbagliata, ma non riesco a pensare ad un altro) delle classi Case in particolare, sembra (per me) più di una funzionalità adatta a tutte le classi. Cosa succede se ho bisogno di copy () sulla mia classe non case? C'è un tratto che posso usare per ottenere quella funzionalità?
ThaDon,

1
Le classi di casi @ThaDon dovrebbero essere definite dai loro parametri di costruzione - la loro uguaglianza, il codice hash e l'estrattore si basano su questo presupposto, così come il metodo di copia. Sulle classi non case, si può immaginare se i parametri del costruttore siano tutto ciò che è necessario per copiare una classe. Puoi, tuttavia, scrivere facilmente il tuo metodo di copia.
Daniel C. Sobral,

11

Bene, in Haskell, gli oggetti sono (di solito) immutabili, quindi i getter (che ottieni quando usi la sintassi dei record) o le funzioni che agiscono come getter sono referenzialmente trasparenti. E poi non si "impostano" i valori sugli oggetti - semmai si crea un nuovo oggetto simile a quello vecchio, ma con un valore diverso per uno dei campi. Anche questa è una funzione pura.


1
"gli oggetti sono (di solito) immutabili" quando non lo sono?
Sara

-1

"Getter e setter hanno l'oggetto come parametro - anche se di solito è implicito - quindi i getter sono referenzialmente trasparenti. - delnan"

Referenzialmente trasparente significa che la funzione restituisce SEMPRE la stessa uscita per gli stessi ingressi; quindi se un attributo oggetto è stato modificato da un setter, non stai restituendo lo stesso output. :)


Ma, se l'oggetto è stato modificato da un setter, l'input al getter (ovvero l'argomento auto implicito) È cambiato.
Stephen C. Steel,

1
Il valore / puntatore di riferimento dell'oggetto non è cambiato a meno che l'oggetto non sia stato spostato sull'heap.
Casey Hawthorne,

5
Sì, ma logicamente, l'input implicito è l'oggetto stesso, non il valore del puntatore.
Stephen C. Steel,

"se un attributo oggetto è stato modificato da un setter, non stai restituendo lo stesso output": in termini funzionali, hai distrutto il primo oggetto e ne hai creato uno nuovo. Per motivi di prestazioni (evitare la copia e l'aggiornamento dei riferimenti dal vecchio al nuovo oggetto) si sta memorizzando il nuovo oggetto nella stessa area di memoria che conteneva il vecchio oggetto.
Giorgio,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.