Cos'è la trasparenza referenziale?


285

Che cosa significa il termine trasparenza referenziale ? Ho sentito che è descritto come "significa che puoi sostituire gli uguali con uguali" ma questa sembra una spiegazione inadeguata.


1
wow mi chiedo perché l'improvvisa impennata della popolarità di questa domanda ...
Claudiu,

1
@claudia: Non posso dirlo con certezza, ma r / haskell ha avuto il vento e molti hanno sentito che Uday stava, sebbene fosse abbastanza preciso, prendendo un po 'di confusione nella comunità.
efrey,

6
@efrey Una stronzata, forse lo era. Ma quando i programmatori funzionali abbattono i linguaggi di programmazione imperativa e i linguaggi funzionali a effetto collaterale (come Lisp e ML) sostenendo che non sono referenzialmente trasparenti, non stanno agitando? Non dovrebbero almeno avere i loro fatti prima di farlo?
Uday Reddy,

2
@Claudiu L'ho pubblicato su Haskell Reddit e Conal lo ha twittato. Ho trovato la discussione interessante e ho pensato che meritasse una discussione più ampia. Ho attirato l'attenzione sull'atmosfera di Uday per stimolare una discussione. Sono d'accordo sul fatto che noi FPer a volte possiamo essere compiacenti e avere bisogno di un buon prodotto - ben fatto a Uday per averlo fornito!
chrisdornan,

7
@efrey. In effetti, è per questo che ho scelto di citare Bird e Wadler (semanticisti?) Nel mio secondo post. Le persone consapevoli sanno che la concezione popolare di trasparenza referenziale è vaga e forse incoerente. Ma non è mai stato spiegato correttamente alla comunità di programmazione. Spero che la mia scrittura qui farà la differenza.
Uday Reddy,

Risposte:


362

Il termine "trasparenza referenziale" deriva dalla filosofia analitica , il ramo della filosofia che analizza i costrutti, le dichiarazioni e gli argomenti del linguaggio naturale basati sui metodi della logica e della matematica. In altre parole, è la materia più vicina al di fuori dell'informatica a ciò che chiamiamo semantica del linguaggio di programmazione . Il filosofo Willard Quine era responsabile dell'avvio del concetto di trasparenza referenziale, ma era anche implicito negli approcci di Bertrand Russell e Alfred Whitehead.

Alla base, la "trasparenza referenziale" è un'idea molto semplice e chiara. Il termine "referente" è usato nella filosofia analitica per parlare della cosa a cui si riferisce un'espressione . È più o meno la stessa cosa che intendiamo per "significato" o "denotazione" nella semantica del linguaggio di programmazione. Usando l'esempio di Andrew Birkett ( post sul blog ), il termine "la capitale della Scozia" si riferisce alla città di Edimburgo. Questo è un semplice esempio di "referente".

Un contesto in una frase è "referenzialmente trasparente" se la sostituzione di un termine in quel contesto con un altro termine che si riferisce alla stessa entità non ne altera il significato. Per esempio

Il parlamento scozzese si riunisce nella capitale della Scozia.

significa lo stesso di

Il Parlamento scozzese si riunisce a Edimburgo.

Quindi il contesto "Il Parlamento scozzese si incontra in ..." è un contesto referenzialmente trasparente. Possiamo sostituire "la capitale della Scozia" con "Edimburgo" senza alterarne il significato. Per dirla in altro modo, il contesto si preoccupa solo di ciò a cui il termine si riferisce e nient'altro. Questo è il senso in cui il contesto è "referenzialmente trasparente".

D'altra parte, nella frase,

Edimburgo è la capitale della Scozia dal 1999.

non possiamo fare un tale rimpiazzo. Se lo facessimo, otterremmo "Edimburgo è Edimburgo dal 1999", che è una cosa folle da dire, e non trasmette lo stesso significato della frase originale. Quindi, sembrerebbe che il contesto "Edimburgo è stato ... dal 1999" è referenzialmente opaco (l'opposto di referenzialmente trasparente). Apparentemente si preoccupa di qualcosa di più di ciò a cui il termine si riferisce. Che cos'è?

Cose come "la capitale della Scozia" sono chiamate termini definiti e per molto tempo non hanno dato mal di testa a logici e filosofi. Russell e Quine li hanno risolti dicendo che in realtà non sono "referenziali", vale a dire, è un errore pensare che gli esempi precedenti siano usati per riferirsi ad entità. Il modo giusto di capire "Edimburgo è la capitale della Scozia dal 1999" è da dire

La Scozia ha una capitale dal 1999 e quella capitale è Edimburgo.

Questa frase non può essere trasformata in una nocciola. Problema risolto! Il punto di Quine era di dire che il linguaggio naturale è disordinato, o almeno complicato, perché è fatto per essere conveniente per l'uso pratico, ma i filosofi e i logici dovrebbero portare chiarezza capendoli nel modo giusto. La trasparenza referenziale è uno strumento da utilizzare per fornire tale chiarezza di significato .

Cosa c'entra tutto ciò con la programmazione? Non molto, in realtà. Come abbiamo detto, la trasparenza referenziale è uno strumento da utilizzare per comprendere il linguaggio, cioè per assegnare significato . Christopher Strachey , che ha fondato il campo della semantica del linguaggio di programmazione, l'ha usato nel suo studio del significato. Il suo documento di base " Concetti fondamentali nei linguaggi di programmazione " è disponibile sul web. È un bellissimo documento e tutti possono leggerlo e capirlo. Quindi, per favore, fallo. Sarai molto illuminato. In questo paragrafo introduce il termine "trasparenza referenziale":

Una delle proprietà più utili delle espressioni è quella chiamata dalla trasparenza referenziale di Quine. In sostanza ciò significa che se vogliamo trovare il valore di un'espressione che contiene una sottoespressione, l'unica cosa che dobbiamo sapere sulla sottoespressione è il suo valore. Qualsiasi altra caratteristica della sottoespressione, come la sua struttura interna, il numero e la natura dei suoi componenti, l'ordine in cui vengono valutati o il colore dell'inchiostro in cui sono scritti, sono irrilevanti per il valore del principale espressione.

L'uso di "in sostanza" suggerisce che Strachey lo sta parafrasando per spiegarlo in termini semplici. I programmatori funzionali sembrano comprendere questo paragrafo a modo loro. Ci sono altre 9 ricorrenze di "trasparenza referenziale" nel documento, ma non sembrano preoccuparsi di nessuna delle altre. In effetti, l'intero documento di Strachey è dedicato alla spiegazione del significato dei linguaggi di programmazione imperativi . Ma oggi i programmatori funzionali affermano che i linguaggi di programmazione imperativa non sono referenzialmente trasparenti. Strachey si sarebbe girato nella sua tomba.

Possiamo salvare la situazione. Abbiamo detto che il linguaggio naturale è "disordinato o almeno complicato" perché è fatto per essere comodo per l'uso pratico. I linguaggi di programmazione sono allo stesso modo. Sono "disordinati, o almeno complicati" perché sono fatti per essere convenienti per un uso pratico. Ciò non significa che debbano confonderci. Devono solo essere capiti nel modo giusto, usando un meta linguaggio che sia referenzialmente trasparente in modo da avere chiarezza di significato. Nel documento che ho citato, Strachey fa esattamente questo. Spiega il significato dei linguaggi di programmazione imperativa suddividendoli in concetti elementari, senza mai perdere la chiarezza da nessuna parte. Una parte importante della sua analisi è sottolineare che le espressioni nei linguaggi di programmazione hanno due tipi di "valori",. Prima del lavoro di Strachey, questo non era compreso e la confusione regnava sovrana. Oggi, la definizione di C lo menziona regolarmente e ogni programmatore C comprende la distinzione. (È difficile dire se i programmatori di altre lingue lo capiscano altrettanto bene.)

Sia Quine che Strachey si preoccupavano del significato delle costruzioni linguistiche che implicano una qualche forma di dipendenza dal contesto. Ad esempio, il nostro esempio "Edimburgo è la capitale della Scozia dal 1999" indica il fatto che "capitale della Scozia" dipende dal momento in cui viene presa in considerazione. Tale dipendenza dal contesto è una realtà, sia nei linguaggi naturali che nei linguaggi di programmazione. Anche nella programmazione funzionale, le variabili libere e legate devono essere interpretate rispetto al contesto in cui appaiono. La dipendenza dal contesto di qualsiasi tipo blocca la trasparenza referenziale in un modo o nell'altro. Se provi a capire il significato dei termini senza tener conto dei contesti da cui dipendono, finiresti di nuovo con confusione. Quine si preoccupava del significato della logica modale. Lo sostennela logica modale era referenzialmente opaca e dovrebbe essere ripulita traducendola in un quadro referenzialmente trasparente (ad esempio, considerando la necessità come provabilità). Ha in gran parte perso questo dibattito. Logici e filosofi allo stesso modo trovarono che la possibile semantica mondiale di Kripke fosse perfettamente adeguata. Una situazione simile regna anche con la programmazione imperativa. La dipendenza dallo stato spiegata da Strachey e la dipendenza dal negozio spiegata da Reynolds (in un modo simile alla possibile semantica mondiale di Kripke) sono perfettamente adeguate. I programmatori funzionali non conoscono molto di questa ricerca. Le loro idee sulla trasparenza referenziale devono essere prese con un grosso granello di sale.

[Nota aggiuntiva: gli esempi sopra illustrano che una semplice frase come "capitale della Scozia" ha più livelli di significato. Ad un certo livello, al momento potremmo parlare della capitale. Ad un altro livello, potremmo parlare di tutte le possibili capitali che la Scozia avrebbe potuto avere nel corso del tempo. Possiamo "ingrandire" un particolare contesto e "rimpicciolire" per estendere abbastanza facilmente tutti i contesti nella pratica normale. L'efficienza del linguaggio naturale si avvale della nostra capacità di farlo. I linguaggi di programmazione imperativi sono efficienti allo stesso modo. Possiamo usare una variabile x sul lato destro di un compito (il valore r ) per parlare del suo valore in uno stato particolare. Oppure, potremmo parlare del suo valore lche abbraccia tutti gli stati. Le persone sono raramente confuse da queste cose. Tuttavia, possono o meno essere in grado di spiegare con precisione tutti gli strati di significato inerenti ai costrutti del linguaggio. Tutti questi livelli di significato non sono necessariamente "ovvi" ed è una questione scientifica studiarli correttamente. Tuttavia, l'inarticolarità della gente comune per spiegare significati così stratificati non implica che siano confusi su di loro.]

Un "poscritto" separato di seguito mette in relazione questa discussione con le preoccupazioni della programmazione funzionale e imperativa .


10
Grazie, ma non ritengo che esista una "evidente" estensione dell'uguaglianza. Quando ho detto che la "capitale della Scozia" si riferisce alla città di Edimburgo, non ci hai pensato due volte. Ma quando ho iniziato a parlare di "dal 1999", improvvisamente ti sei reso conto che c'è del tempo. Quindi, la nozione estensiva di uguaglianza può essere abbastanza sottile ed è formalizzata dai ricercatori del linguaggio di programmazione. Le persone che vogliono avere una perfetta comprensione dell'uguaglianza estensiva devono imparare i frutti di quella ricerca. Potrebbe non essere affatto "ovvio".
Uday Reddy,

5
Fantastico! Un gradito sollievo alle idee sbagliate popolari su RT, ad esempio, legandolo a funzioni . O definendo sostituendo un'espressione con il suo valore (come su Wikipedia) - stranamente perché espressioni e valori sono diversi tipi di cose. Forse un posto in cui le persone sbagliano nel considerare l'RT dei linguaggi imperativi è supporre che questi "valori" siano cose semplici come numeri piuttosto che cose più complesse come funzioni di un negozio.
Conal,

13
@sclv Per quanto riguarda l'impatto più ampio della filosofia analitica sull'Informatica, dovrei dire che l'Informatica, come la conosciamo, è stata fondata da Godel, Church, Kleene e Turing. Queste persone erano logici e avevano una buona conoscenza degli aspetti matematici e filosofici della logica, in particolare delle tradizioni di Peano, Frege, Russell, Whitehead, Carnap e Quine. I primi pionieri della moderna Informatica conoscevano le connessioni. Ma la rapida crescita dell'Informatica li ha recisi. Dobbiamo tornare da loro.
Uday Reddy,

5
La logica @sclv è tradizionalmente interpretata come la scienza delle conseguenze . Ma penso che sia un più ampio. È la scienza dell'informazione . Quine, vedo come il primo che ha portato alla visione più ampia. "Parola e oggetto" è un'analisi del contenuto informativo delle dichiarazioni in linguaggio naturale. Tuttavia, né i filosofi né i matematici hanno mai avuto un interesse attivo nei calcoli , il che è abbastanza sconcertante, dato che il calcolo centrale è stato per la civiltà e la scienza da tempo immemorabile. Dobbiamo trovare il modo di interessarli.
Uday Reddy,

3
@Conal: ho aggiunto una nuova risposta che amplifica il tuo punto. Probabilmente sarà in fondo alla pagina.
Uday Reddy,

134

Trasparenza referenziale, un termine comunemente usato nella programmazione funzionale, significa che data una funzione e un valore di input, riceverai sempre lo stesso output. Vale a dire che non esiste uno stato esterno utilizzato nella funzione.

Ecco un esempio di una funzione trasparente referenziale:

int plusOne(int x)
{
  return x+1;
}

Con una funzione trasparente referenziale, dati un input e una funzione, è possibile sostituirlo con un valore invece di chiamare la funzione. Quindi, invece di chiamare plusOne con un parametro di 5, potremmo semplicemente sostituirlo con 6.

Un altro buon esempio è la matematica in generale. In matematica, data una funzione e un valore di input, verrà sempre mappato sullo stesso valore di output. f (x) = x + 1. Pertanto le funzioni in matematica sono referenzialmente trasparenti.

Questo concetto è importante per i ricercatori perché significa che quando si ha una funzione referenzialmente trasparente, si presta a una facile parallelizzazione automatica e memorizzazione nella cache.

La trasparenza referenziale viene utilizzata sempre in linguaggi funzionali come Haskell.

-

Al contrario c'è il concetto di opacità referenziale. Questo significa il contrario. La chiamata alla funzione potrebbe non produrre sempre lo stesso output.

//global G
int G = 10;

int plusG(int x)
{//G can be modified externally returning different values.
  return x + G;
}

Un altro esempio è una funzione membro in un linguaggio di programmazione orientato agli oggetti. Le funzioni membro operano comunemente sulle sue variabili membro e pertanto sarebbero opache referenziali. Naturalmente le funzioni dei membri possono essere trasparenti dal punto di vista referenziale.

Ancora un altro esempio è una funzione che legge da un file di testo e stampa l'output. Questo file di testo esterno potrebbe cambiare in qualsiasi momento, quindi la funzione sarebbe referenzialmente opaca.


1
Solo un avvertimento, è possibile avere un oggetto completamente referenzialmente trasparente, con funzioni membro referenzialmente trasparenti. Vedi okmij.org/ftp/Scheme/oop-in-fp.txt
Jonathan Arkell,

1
Ed ecco il codice di cui si parla in quell'articolo: okmij.org/ftp/Scheme/pure-oo-system.scm
Jonathan Arkell,

Nel caso di una classe completamente referenzialmente trasparente, probabilmente tutte le funzioni membro saranno statiche.
Brian R. Bondy,

13
Quello di cui stai parlando qui non è la trasparenza referenziale, sebbene sia comunemente indicato come tale. Vedi le due risposte di Uday e i loro commenti. In particolare, ciò che chiamate "output" non è la denotazione. Se sostituissi "plusG 3" con qualsiasi altra espressione avente lo stesso valore / denotazione, otterrai effettivamente un programma con lo stesso significato, quindi RT mantiene le lingue imperative. L'espressione "3 + 10" o "13" non ha lo stesso significato di "plusG 3", poiché il significato nei linguaggi imperativi è una funzione del "negozio" (stato).
Conal,

1
Ho appena letto un articolo sugli effetti collaterali e il cambio di stato e ho intuito che ha qualcosa a che fare con RT. Potresti aggiungere una nota per favore?
Gaurav,

91

Una funzione referenzialmente trasparente è una funzione che dipende solo dal suo input.


4
Ecco perché è difficile nella programmazione OO perché gli oggetti hanno stato.
Kris,

5
Quindi è corretto dire che "referenzialmente trasparente" è identico a "deterministico" quando si descrivono le funzioni? In caso contrario, qual è la differenza tra i due termini?
mwolfe02,

1
Questo suona anche come una definizione di una funzione "pura".
Evgeny A.

75

[Questo è un post scriptum per la mia risposta del 25 marzo, nel tentativo di avvicinare la discussione alle preoccupazioni della programmazione funzionale / imperativa.]

L'idea dei programmatori funzionali di trasparenza referenziale sembra differire dalla nozione standard in tre modi:

  • Mentre i filosofi / logici usano termini come "riferimento", "denotazione", "designatum" e " bedeutung " (termine tedesco di Frege), i programmatori funzionali usano il termine "valore". (Non è del tutto ciò che fanno. Noto che Landin, Strachey e i loro discendenti hanno anche usato il termine "valore" per parlare di riferimento / denotazione. Potrebbe essere solo una semplificazione terminologica introdotta da Landin e Strachey, ma sembra fare grande differenza se usato in modo ingenuo.)

  • I programmatori funzionali sembrano credere che questi "valori" esistano all'interno del linguaggio di programmazione, non all'esterno. Nel fare ciò, differiscono sia dai filosofi che dai semantisti del linguaggio di programmazione.

  • Sembrano credere che questi "valori" dovrebbero essere ottenuti mediante valutazione.

Ad esempio, l'articolo di Wikipedia sulla trasparenza referenziale dice questa mattina:

Si dice che un'espressione è referenzialmente trasparente se può essere sostituita con il suo valore senza cambiare il comportamento di un programma (in altre parole, produrre un programma che ha gli stessi effetti e output sullo stesso input).

Ciò è completamente in contrasto con ciò che dicono i filosofi / i logici. Dicono che un contesto è referenziale o referenzialmente trasparente se un'espressione in quel contesto può essere sostituita da un'altra espressione che si riferisce alla stessa cosa ( un'espressione coreferenziale ). Chi sono questi filosofi / logici? Includono Frege , Russell , Whitehead , Carnap , Quine , Churche innumerevoli altri. Ognuno di loro è una figura imponente. Il potere intellettuale combinato di questi logici è a dir poco sconvolgente. Tutti loro sono unanimi nella posizione che referenti / denotazioni esistono al di fuori del linguaggio formale e le espressioni all'interno del linguaggio può parlare solo su di loro. Quindi, tutto ciò che si può fare all'interno della lingua è sostituire un'espressione con un'altra espressione che si riferisce alla stessa entità. I riferimenti / denotazioni stessi non esistono nella lingua. Perché i programmatori funzionali si discostano da questa tradizione consolidata?

Si potrebbe presumere che i semantisti del linguaggio di programmazione li abbiano indotti in errore. Ma non lo fecero.

Landin :

(a) ogni espressione ha una struttura di sottoespressione nidificante, (b) ogni sottoespressione indica qualcosa (di solito un numero, un valore di verità o una funzione numerica) , (c) la cosa che un'espressione indica, cioè il suo "valore", dipende solo dal valori delle sue sottoespressioni, non su altre loro proprietà. [Enfasi aggiunta]

Stoy :

L'unica cosa che conta su un'espressione è il suo valore e qualsiasi sottoespressione può essere sostituita da qualsiasi altro valore uguale [Enfasi aggiunta]. Inoltre, il valore di un'espressione è, entro certi limiti, lo stesso ogni volta che si verifica ".

Bird and Wadler :

il valore di un'espressione dipende solo dai valori delle sue espressioni costitutive (se presenti) e queste sottoespressioni possono essere sostituite liberamente da altre che possiedono lo stesso valore [enfasi aggiunta].

Quindi, a posteriori, gli sforzi di Landin e Strachey per semplificare la terminologia sostituendo "riferimento" / "denotazione" con "valore" potrebbero essere stati ingiuriosi. Non appena si sente parlare di un "valore", c'è la tentazione di pensare a un processo di valutazione che lo conduce. È altrettanto allettante pensare a qualunque cosa la valutazione produca come "valore", anche se potrebbe essere abbastanza chiaro che questa non è la denotazione. Questo è ciò che ritengo sia successo al concetto di "trasparenza referenziale" agli occhi dei programmatori funzionali. Ma il "valore" di cui parlavano i primi semantisti non è il risultato di una valutazione o dell'output di una funzione o qualcosa del genere. È la denotazione del termine.

Una volta compreso il cosiddetto "valore" di un'espressione ("riferimento" o "denotazione" nel discorso dei filosofi classici) come un complesso oggetto matematico / concettuale, si aprono tutti i tipi di possibilità.

  • Strachey ha interpretato le variabili nei linguaggi di programmazione imperativa come valori L , come menzionato nella mia risposta del 25 marzo, che è un oggetto concettuale sofisticato che non ha una rappresentazione diretta nella sintassi di un linguaggio di programmazione.
  • Ha anche interpretato i comandi in tali lingue come funzioni da stato a stato, un'altra istanza di un oggetto matematico complesso che non è un "valore" all'interno della sintassi.
  • Anche una chiamata di funzione con effetti collaterali in C ha un "valore" ben definito come trasformatore di stato che mappa gli stati a coppie di stati e valori (la cosiddetta "monade" nella terminologia dei programmatori funzionali).

La riluttanza dei programmatori funzionali a chiamare tali linguaggi "referenzialmente trasparenti" implica semplicemente che sono riluttanti ad ammettere oggetti matematici / concettuali complessi come "valori". D'altra parte, sembrano perfettamente disposti a chiamare un trasformatore di stato un "valore" quando viene inserito nella propria sintassi preferita e vestito con una parola vivace come "monade". Devo dire che sono del tutto incoerenti, anche se garantiamo loro che la loro idea di "trasparenza referenziale" ha una certa coerenza.

Un po 'di storia potrebbe far luce su come sono nate queste confusioni. Il periodo tra il 1962 e il 1967 fu molto intenso per Christopher Strachey. Tra il 1962 e il 1965 prese un lavoro part-time come assistente di ricerca con Maurice Wilkes per progettare e implementare il linguaggio di programmazione che divenne noto come CPL. Questo era un linguaggio di programmazione indispensabile ma doveva avere anche potenti capacità di linguaggio di programmazione funzionale. Landin, che era un dipendente di Strachey nella sua società di consulenza, ebbe un'enorme influenza sulla visione di Strachey dei linguaggi di programmazione. Nel documento di riferimento del 1965 "I prossimi 700 linguaggi di programmazione ", Landin promuove in modo inopportuno i linguaggi di programmazione funzionale (chiamandoli denotativilinguaggi) e descrive i linguaggi di programmazione imperativa come la loro "antitesi". Nella discussione che segue, troviamo che Strachey solleva dubbi sulla forte posizione di Landin.

... I DL formano un sottoinsieme di tutte le lingue. Sono un sottoinsieme interessante, ma che è scomodo da usare se non ci si è abituati. Ne abbiamo bisogno perché al momento non sappiamo come costruire prove con linguaggi che includono imperativi e salti. [Enfasi aggiunta]

Nel 1965, Strachey prese il posto di Reader ad Oxford e sembra aver lavorato essenzialmente a tempo pieno nello sviluppo di una teoria di imperativi e salti. Nel 1967, era pronto con una teoria, che ha insegnato nel suo corso su " Concetti fondamentali in linguaggi di programmazione " in una scuola estiva di Copenaghen. Gli appunti delle lezioni avrebbero dovuto essere pubblicati ma "sfortunatamente, a causa della redazione dilatoria, il procedimento non si è mai materializzato; come gran parte del lavoro di Strachey a Oxford, tuttavia, il giornale ha avuto un'influente circolazione privata". ( Martin Campbell-Kelly )

La difficoltà di ottenere gli scritti di Strachey avrebbe potuto portare alla propagazione delle confusioni, con la gente che faceva affidamento su fonti secondarie e sentito dire. Ma, ora che " Concetti fondamentali " sono prontamente disponibili sul web, non è necessario ricorrere a indovinare il lavoro. Dovremmo leggerlo e prendere una decisione su ciò che significava Strachey. In particolare:

  • Nella sezione 3.2, si occupa di "espressioni" in cui parla di "trasparenza referenziale di valore R".
  • La sua sezione 3.3 tratta dei "comandi" in cui parla di "trasparenza referenziale di valore L".
  • Nella sezione 3.4.5, parla di "funzioni e routine" e dichiara che "qualsiasi partenza della trasparenza referenziale del valore R in un contesto di valore R dovrebbe essere eliminata decomprimendo l'espressione in diversi comandi ed espressioni più semplici, oppure, se questo risulta essere difficile, oggetto di un commento ".

Qualsiasi discorso sulla "trasparenza referenziale" senza comprendere la distinzione tra valori L, valori R e altri oggetti complessi che popolano l'universo concettuale del programmatore imperativo è fondamentalmente sbagliato.


10
Penso che valga la pena sottolineare che confondere queste due nozioni di "valore" (valutazioni contro denotazioni) induce in errore i programmatori funzionali nella loro critica ai linguaggi imperativi , dove il divario tra le nozioni è grande.
Conal,

8
cioè, la nozione di valutazione porta alla conclusione che le lingue imperative non sono RT, mentre la nozione di denotazione no.
Conal,

12
Mi sembra che una volta che hai inchiodato completamente la semantica denotazionale di una lingua, non può fare a meno di essere referenzialmente trasparente. Quindi questo equivale a dire che il termine non è utile per quanto riguarda i linguaggi di programmazione.
Tom Crockett,

20
Quindi sembra che la gente abbia l'abitudine di usare un termine per significare qualcosa di materialmente diverso da quello che gli altri intendevano quando usavano quel termine in passato. A cui dico: benvenuto in lingua inglese.
Daniel Pratt

17
@DanielPratt: se la libertà degli effetti collaterali è ciò che vogliono dire i programmatori funzionali, allora perché lo chiamano "trasparenza referenziale"? Possono semplicemente chiamarlo "libertà degli effetti collaterali", che è un'idea perfettamente chiara. Nessuno dovrà chiedere su stackexchange cosa significa "libertà degli effetti collaterali". Dov'è la necessità di rubare termini classici grandiosi che nessuno sembra capire?
Uday Reddy,

23

Un'espressione è referenzialmente trasparente se può essere sostituita con il suo valore, senza modificare l'algoritmo, producendo un algoritmo che ha gli stessi effetti e output sullo stesso input.


18

Una funzione referenzialmente trasparente è una funzione che agisce come una funzione matematica; dati gli stessi input, produrrà sempre gli stessi output. Implica che lo stato passato non viene modificato e che la funzione non ha uno stato proprio.


10

Per coloro che hanno bisogno di una spiegazione concisa ne rischierò uno (ma leggi l'informativa di seguito).

La trasparenza referenziale in un linguaggio di programmazione promuove il ragionamento equazionale: maggiore è la trasparenza referenziale, più facile è fare ragionamenti equazionali. Ad esempio con una definizione di funzione (pseudo),

fx = x + x,

la facilità con cui puoi (tranquillamente) sostituire f (foo) con foo + foo nell'ambito di questa definizione, senza avere troppi vincoli su dove è possibile eseguire questa riduzione, è una buona indicazione di quanta trasparenza referenziale il tuo linguaggio di programmazione ha.

Ad esempio se foo fosse x ++ nel senso della programmazione C, allora non potresti eseguire questa riduzione in modo sicuro (vale a dire, se dovessi eseguire questa riduzione non finiresti con lo stesso programma con cui hai iniziato).

Nei pratici linguaggi di programmazione non vedrai la perfetta trasparenza referenziale ma i programmatori funzionali se ne occupano più della maggior parte (cfr. Haskell, dove è un obiettivo fondamentale).

(Informativa completa: sono un programmatore funzionale, quindi dalla risposta migliore dovresti prendere questa spiegazione con un granello di sale.)


3
Non ho alcun problema con le lingue che facilitano il ragionamento equazionale. Ma contesterei il fatto che abbia qualcosa a che fare con la "trasparenza referenziale" come definita in modo classico. In secondo luogo, come programmatore pratico, penso che il ragionamento equazionale sia sopravvalutato. Il ragionamento che è importante nella pratica ha a che fare con pre-condizioni, post-condizioni, invarianti e astrazione dei dati. Per le persone che fanno affidamento su tali tecniche di ragionamento, gli effetti collaterali non sembrano avere molta importanza. Quindi, anche se concordo con te sul fatto che gli effetti collaterali delle espressioni siano una cattiva idea, non sembrano rappresentare un argomento killer.
Uday Reddy,

1
@UdayReddy Solo perché i programmatori funzionali hanno scelto un particolare metodo per comporre la trasparenza referenziale nei loro programmi (eliminando gli effetti collaterali e sviluppando una algebra di programmi sofisticata e potente), o hanno alcuni professionisti che probabilmente non capiscono la trasparenza referenziale così come pensano di sì, non significa che i linguaggi di programmazione funzionale non riescano ad aumentare la trasparenza referenziale o che i programmatori di linguaggi funzionali e gli autori di compilatori non stiano sfruttando questo aumento della tracciabilità formale per molti scopi positivi.
Chrisdornan,

2
Chris: Uday ha sottolineato che Strachey ha eliminato il problema dell'opacità referenziale nella semantica del linguaggio di programmazione, in particolare per i linguaggi imperativi. Quindi i programmatori funzionali non possono "comporre la trasparenza referenziale nei loro programmi". Come esempio concreto, Haskell IO non è di aiuto con RT esattamente perché non è necessario alcun aiuto di RT.
Conal,

2
@chrisdornan: mi dispiace per il mio primo commento sopra. Io stesso ho avuto difficoltà a capire cosa stavo cercando di dire nelle prime due frasi :-( Ma ecco una spiegazione. Prendi in considerazione un calcolo di stadiazione a due o più livelli. Ogni operatore di stadiazione è referenzialmente opaco. È in effetti , un operatore di quotazione. Tuttavia, puoi fare perfettamente il ragionamento equazionale all'interno di ogni fase. Quindi, ogni operatore referenzialmente opaco imposta i limiti per il ragionamento equazionale. Ma hai ancora un ragionamento equazionale all'interno di quei confini.
Uday Reddy

1
@chrisdomain: Inoltre, pochissime persone vorrebbero essere puristi referenziali per la trasparenza in modo da bandire tali operatori della stadiazione. Questi operatori sono estremamente utili. Programmare senza di loro facendo la stadiazione manualmente sarebbe noioso, soggetto a errori e brutto. E fare una messa in scena manualmente non ti comprerebbe un ragionamento più equo di quello che avevi prima. Quindi, proibire buoni dispositivi di programmazione nella ricerca purista del ragionamento equazionale sarebbe come tagliare il naso per far dispetto al tuo viso.
Uday Reddy,

8

Se sei interessato all'etimologia (es. Perché questo concetto ha questo nome particolare), dai un'occhiata al mio post sul blog sull'argomento. La terminologia deriva dal filosofo / logico Quine.


4
  1. La semantica denotazionale si basa sui linguaggi di modellazione costruendo domini che costituiscono valori denotabili .
  2. I programmatori funzionali usano il termine valore per descrivere la convergenza di un calcolo basato sulle regole di riscrittura della lingua, ad es. la sua semantica operativa.

In 1 c'è una chiarezza di due lingue in questione:

  • quello che viene modellato, il linguaggio degli oggetti
  • il linguaggio della modellazione, il meta linguaggio

In 2, grazie alla vicinanza dell'oggetto e ai metalinguaggi, possono essere confusi.

Come implementatore di linguaggio, trovo che devo ricordare costantemente questa distinzione.

Quindi il Prof. Reddy posso parafrasarti così :-)

Nel contesto della programmazione funzionale e della semantica, il termine Trasparenza referenziale non è trasparente dal punto di vista referenziale.


1
Ah ah Grazie per la spiegazione. Il problema è anche che i programmatori funzionali agiscono come se avessero una nozione generale di "trasparenza referenziale" applicabile a tutti i linguaggi di programmazione . Ma questo dipende dalla loro nozione di "valore", che può o meno avere senso per altre lingue. Per rivendicare una teoria generale della "trasparenza referenziale", devono produrre una "teoria" generale della teoria. Finora manca.
Uday Reddy,

4

Spero che la seguente risposta aggiunga e qualifichi le controverse 1a e 3a risposta.

Concediamo che un'espressione denota o si riferisce a qualche referente. Tuttavia, una domanda è se questi referenti possono essere codificati isomorficamente come parte delle espressioni stesse, chiamando tali espressioni "valori". Ad esempio, i valori numerici letterali sono un sottoinsieme dell'insieme di espressioni aritmetiche, i valori di verità sono un sottoinsieme dell'insieme di espressioni booleane, ecc. L'idea è di valutare un'espressione al suo valore (se ne ha una). Quindi la parola "valore" può riferirsi a una denotazione oa un elemento distinto dell'insieme di espressioni. Ma se c'è un isomorfismo (una biiezione) tra il referente e il valore, possiamo dire che sono la stessa cosa. (Detto questo, bisogna fare attenzione a definire i referenti e l'isomorfismo, come dimostrato dal campo della semantica denotazionale. Per fare un esempio menzionato dalle risposte alla terza risposta,data Nat = Zero | Suc Nat non corrisponde come previsto all'insieme dei numeri naturali.)

Scriviamo E[·]per un'espressione con un buco, noto anche in alcuni settori come un "contesto". Due esempi di contesto per espressioni simili a C sono [·]+1e [·]++.

Scriviamo [[·]]per la funzione che accetta un'espressione (senza buchi) e fornisce il suo significato (referente, denotazione, ecc.) In un universo che fornisce significato. (Prendo in prestito la notazione dal campo della semantica denotazionale.)

Adattiamo la definizione di Quine in qualche modo formalmente come segue: un contesto E[·] è referenzialmente trasparente se dato due espressioni E1e E2(senza buchi lì) tale che [[E1]] = [[E2]](cioè le espressioni denotano / si riferiscono allo stesso referente), allora è il caso [[E[E1]]] = [[E[E2]]](cioè riempiendo -nel buco con uno E1o E2risultati in espressioni che denotano anche lo stesso referente).

La regola di Leibniz di sostituire gli uguali con uguali è in genere espressa come 'if E1 = E2then E[E1] = E[E2]', che dice che E[·]è una funzione. Una funzione (o del resto un programma che calcola la funzione) è una mappatura da una sorgente a una destinazione in modo che vi sia al massimo un elemento target per ogni elemento sorgente. Le funzioni non deterministiche sono termini impropri, sono o relazioni, funzioni che forniscono insiemi, ecc. Se nella regola di Leibniz l'uguaglianza =è denotazionale, le doppie parentesi sono semplicemente date per scontate ed eluse. Quindi un contesto referenzialmente trasparente è una funzione. E la regola di Leibniz è l'ingrediente principale del ragionamento equazionale, quindi il ragionamento equazionale è sicuramente correlato alla trasparenza referenziale.

Sebbene [[·]]sia una funzione dalle espressioni alle denotazioni, potrebbe essere una funzione dalle espressioni ai "valori" intesi come sottoinsieme limitato di espressioni e [[·]]può essere inteso come valutazione.

Ora, se E1è un'espressione ed E2è un valore, abbiamo ciò che penso sia inteso dalla maggior parte delle persone nel definire la trasparenza referenziale in termini di espressioni, valori e valutazione. Ma come illustrato dalla prima e terza risposta in questa pagina, questa è una definizione imprecisa.

Il problema con contesti come quello [·]++non è l'effetto collaterale, ma che il suo valore non è definito in C isomorficamente al suo significato. Le funzioni non sono valori (bene, i puntatori alle funzioni lo sono) mentre lo sono nei linguaggi di programmazione funzionale. Landin, Strachey e i pionieri della semantica denotazionale erano abbastanza intelligenti nell'usare mondi funzionali per fornire significato.

Per i linguaggi imperativi di tipo C possiamo (approssimativamente) fornire semantica alle espressioni usando la funzione [[·]] : Expression -> (State -> State x Value).

Valueè un sottoinsieme di Expression. Statecontiene coppie (identificatore, valore). La funzione semantica prende un'espressione e offre come significato una funzione dallo stato corrente alla coppia con lo stato aggiornato e un valore. Ad esempio, [[x]]è la funzione dallo stato corrente alla coppia il cui primo componente è lo stato corrente e il cui secondo componente è il valore di x. Al contrario, [[x++]]è la funzione dallo stato corrente alla coppia il cui primo componente è uno stato in cui il valore di x viene incrementato e il cui secondo componente è proprio quel valore. In questo senso, il contesto [·]++è referenzialmente trasparente se soddisfa la definizione di cui sopra.

Penso che i programmatori funzionali abbiano il diritto di usare la trasparenza referenziale, nel senso che recuperano naturalmente [[·]]come una funzione dalle espressioni ai valori. Le funzioni sono valori di prima classe e lo stato può anche essere un valore, non una denotazione. La monade dello stato è (in parte) un meccanismo pulito per passare (o infilare) lo stato.


Presumibilmente le risposte "1 °" e "3 °" sono rispettivamente le risposte "25 marzo" e "PostScript" di UdayReddy. Gli ordinali non sono un buon modo per fare riferimento alle risposte in SO. Non solo i voti e le accettazioni possono cambiare nel tempo, ma ci sono più ordini selezionabili.
philipxy,

2

Nota che questo concetto di "significato" è qualcosa che accade nella mente dell'osservatore. Pertanto, lo stesso "riferimento" può significare cose diverse per persone diverse. Quindi, per esempio, abbiamo una pagina di disambiguazione di Edimburgo in Wikipedia.

Un problema correlato che può presentarsi nel contesto della programmazione potrebbe essere il polimorfismo.

E forse dovremmo avere un nome per il caso speciale del polimorfismo (o forse anche del casting) in cui ai nostri scopi i diversi casi polimorfici sono semanticamente equivalenti (al contrario di essere semplicemente simili. Ad esempio, il numero 1 - che potrebbe essere rappresentato usando un tipo intero, o un tipo complesso o uno qualsiasi di una varietà di altri tipi - può essere trattato polimorficamente).


0

Ho trovato utile la definizione di trasparenza referenziale nel libro " Struttura e implementazione dei programmi per computer " (il libro della procedura guidata) perché è integrata da una spiegazione di come viene violata la trasparenza referenziale introducendo l' operazione di assegnazione . Scopri il seguente mazzo di diapositive che ho fatto sull'argomento: https://www.slideshare.net/pjschwarz/introducing-assignment-invalidates-the-substitution-model-of-evaluation-and-violates-referential-transparency-as- ha spiegato-in-SICP-the-wizard-book


0

La trasparenza referenziale può essere semplicemente definita come:

  • Un'espressione che valuta sempre lo stesso risultato in qualsiasi contesto [1] ,
  • Una funzione, se due volte gli stessi parametri, deve produrre lo stesso risultato due volte [2] .

Ad esempio, il linguaggio di programmazione Haskell è un linguaggio funzionale puro; nel senso che è referenzialmente trasparente.

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.