Quali sono i vantaggi della trasparenza referenziale per un programmatore?

18

Nella programmazione, quali sono i vantaggi della trasparenza referenziale ?

RT fa una delle maggiori differenze tra paradigmi funzionali e imperativi ed è spesso usato dai sostenitori del paradigma funzionale come un chiaro vantaggio rispetto all'imperativo; ma in tutti i loro sforzi, questi sostenitori non spiegano mai perché è un vantaggio per me come programmatore .

Certo, avranno le loro spiegazioni accademiche su come è "puro" ed "elegante", ma come fa a farlo meglio di un codice meno "puro"? In che modo mi avvantaggia nella mia programmazione quotidiana?

Nota: questo non è un duplicato di Cos'è la trasparenza referenziale ? Quest'ultimo affronta il tema di che è RT, mentre questa domanda ne descrive i vantaggi (che potrebbero non essere così intuitivi).

    
posta Eyal Roth 13.11.2016 - 14:04
fonte

4 risposte

38

Il vantaggio è che le funzioni pure rendono il codice più facile da ragionare. In altre parole, gli effetti collaterali aumentano la complessità del tuo codice.

Fai un esempio del metodo computeProductPrice .

Un metodo puro ti chiederebbe una quantità di prodotto, una valuta, ecc. Sai che ogni volta che il metodo viene chiamato con gli stessi argomenti, produce sempre lo stesso risultato.

  • Puoi persino memorizzarlo nella cache e utilizzare la versione cache.
  • Puoi renderlo pigro e posticipare la chiamata quando ne hai effettivamente bisogno, sapendo che il valore non cambierà nel frattempo.
  • Puoi chiamare il metodo più volte, sapendo che non avrà effetti collaterali.
  • Puoi ragionare sul metodo stesso in un isolamento dal mondo, sapendo che tutto ciò di cui ha bisogno sono gli argomenti.

Un metodo non puro sarà più complesso da usare e da correggere. Dal momento che dipende dallo stato delle variabili oltre che dagli argomenti e possibilmente modificandoli, significa che potrebbe produrre risultati diversi se chiamati più volte, o non avere lo stesso comportamento quando non vengono chiamati o chiamati troppo presto o troppo tardi.

Esempio

Immagina che ci sia un metodo nel framework che analizza un numero:

decimal math.parse(string t)

Non ha trasparenza referenziale, perché dipende da:

  • La variabile di ambiente che specifica il sistema di numerazione, ovvero Base 10 o qualcos'altro.

  • La variabile all'interno della libreria math che specifica la precisione dei numeri da analizzare. Quindi con il valore di 1 , l'analisi della stringa "12.3456" darà 12.3 .

  • La cultura, che definisce la formattazione prevista. Ad esempio, con fr-FR , l'analisi di "12.345" darà 12345 , perché il carattere di separazione deve essere , , non .

Immagina quanto sia facile o difficile lavorare con tale metodo. Con lo stesso input, puoi avere risultati radicalmente diversi a seconda del momento in cui chiami il metodo, perché qualcosa, da qualche parte, ha cambiato la variabile d'ambiente o ha cambiato la cultura o ha impostato una precisione diversa. Il carattere non deterministico del metodo porterebbe a più bachi e più incubo di debug. Chiamare math.parse("12345") e ottenere 5349 come risposta dal momento che alcuni codici paralleli stavano analizzando i numeri ottali non è bello.

Come risolvere questo metodo ovviamente rotto? Introducendo la trasparenza referenziale. In altre parole, eliminando lo stato globale e spostando tutto sui parametri del metodo:

decimal math.parse(string t, base=10, precision=20, culture=cultures.en_us)

Ora che il metodo è puro, sai che non importa quando chiami il metodo, produrrà sempre lo stesso risultato per gli stessi argomenti.

    
risposta data 13.11.2016 - 14:55
fonte
11

Aggiungete spesso un break point a un punto del vostro codice ed eseguite l'app nel debugger per capire cosa sta succedendo? Se lo fai, questo è in gran parte perché non stai usando la trasparenza referenziale (RT) nei tuoi progetti. E così devi eseguire il codice per capire cosa fa.

L'intero punto di RT è che il codice è altamente deterministico, cioè puoi leggere il codice e capire cosa fa, ogni volta, per lo stesso insieme di input. Una volta che inizi ad aggiungere variabili mutanti, alcune delle quali hanno portata oltre una singola funzione, non puoi semplicemente leggere il codice. Tale codice deve essere eseguito, sia nella tua testa che nel debugger, per capire come funziona veramente.

Il codice più semplice è leggere e ragionare, più è semplice mantenere e individuare i bug, quindi risparmia tempo e denaro per te e il tuo datore di lavoro.

    
risposta data 13.11.2016 - 14:52
fonte
9

La gente usa il termine "più facile ragionare", ma non spiega mai cosa significhi. Considera il seguente esempio:

result1 = foo("bar", 12)
// 100 lines of code
result2 = foo("bar", 12)

Sono result1 e result2 uguali o diversi? Senza trasparenza referenziale, non hai idea. Devi effettivamente leggere il corpo di foo per essere sicuro, e possibilmente il corpo di qualsiasi funzione foo chiama, e così via.

Le persone non si accorgono di questo fardello perché sono abituate ad esso, ma se vai a lavorare in un ambiente puramente funzionale per un mese o due poi torna indietro lo sentirai, ed è un enorme affare .

Ci sono così tanti meccanismi di difesa che le persone fanno per aggirare la mancanza di trasparenza referenziale. Per il mio piccolo esempio, potrei voler mantenere result1 in memoria, perché non saprei se cambierebbe. Poi ho il codice con due stati: prima result1 è stato memorizzato e dopo. Con la trasparenza referenziale, posso semplicemente ricalcolarlo facilmente, purché il ricalcolo non richieda molto tempo.

    
risposta data 13.11.2016 - 19:37
fonte
6

Direi che la trasparenza referenziale è utile non solo per la programmazione funzionale, ma per chiunque lavori con le funzioni perché segue il principio del minimo stupore.

Hai una funzione e puoi ragionare meglio su ciò che fa perché non ci sono fattori esterni che devi prendere in considerazione, per un dato input l'output sarà sempre lo stesso. Anche nel mio imperativo linguaggio cerco di seguire il più possibile questo paradigma, la cosa successiva che sostanzialmente segue automaticamente è: piccole funzioni facili da capire invece delle orribili funzioni di linea 1000+ a cui talvolta corro.

Quelle grandi funzioni fanno magie e ho paura di toccarle perché possono rompere in modo spettacolare.

Quindi le funzioni pure non sono qualcosa solo per la programmazione funzionale, ma per ogni programma.

    
risposta data 13.11.2016 - 14:58
fonte

Leggi altre domande sui tag