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.