O que é transparência referencial?

285

O que significa o termo transparência referencial ? Ouvi isso descrito como "significa que você pode substituir iguais por iguais", mas isso parece ser uma explicação inadequada.

Claudiu
fonte
1
wow eu quero saber porque o súbito aumento na popularidade de esta pergunta ...
Claudiu
1
@claudia: Não posso ter certeza, mas o r / haskell ficou sabendo e muitos acharam que Uday estava, apesar de bastante preciso, dando uma piada na comunidade.
efrey
6
@efrey Uma piada, talvez tenha sido. Mas, quando os programadores funcionais derrubam linguagens de programação imperativas e linguagens funcionais de efeito colateral (como Lisp e ML), alegando que não são referencialmente transparentes, elas não estão gostando? Eles não deveriam ao menos acertar seus fatos antes de fazê-lo?
Uday Reddy
2
@ Claudiu Tenho postado no Haskell Reddit e a Conal tem twittado. Achei a discussão interessante e achei que merecia uma discussão mais ampla. Chamei a atenção da piada de Uday para estimular uma discussão. Concordo que os FPers às vezes podem ser complacentes e precisam de um bom produto - bem feito à Uday por fornecê-lo!
chrisdornan
7
@efrey. De fato, foi por isso que escolhi citar Bird e Wadler (semanticistas?) No meu segundo post. As pessoas conhecedoras sabem que a concepção popular de transparência referencial é vaga e possivelmente incoerente. Mas isso nunca foi explicado adequadamente à comunidade de programação. Espero que meus escritos aqui façam a diferença.
amigos estão dizendo sobre uday reddy

Respostas:

362

O termo "transparência referencial" vem da filosofia analítica , o ramo da filosofia que analisa construções, declarações e argumentos da linguagem natural com base nos métodos da lógica e da matemática. Em outras palavras, é o assunto mais próximo fora da ciência da computação do que chamamos de semântica da linguagem de programação . O filósofo Willard Quine foi responsável por iniciar o conceito de transparência referencial, mas também estava implícito nas abordagens de Bertrand Russell e Alfred Whitehead.

Na sua essência, "transparência referencial" é uma idéia muito simples e clara. O termo "referente" é usado na filosofia analítica para falar sobre o que uma expressão se refere . É aproximadamente o mesmo que queremos dizer com "significado" ou "denotação" na semântica da linguagem de programação. Usando o exemplo de Andrew Birkett ( postagem no blog ), o termo "capital da Escócia" se refere à cidade de Edimburgo. Esse é um exemplo direto de um "referente".

Um contexto em uma frase é "referencialmente transparente" se a substituição de um termo nesse contexto por outro termo que se refere à mesma entidade não altera o significado. Por exemplo

O Parlamento escocês se reúne na capital da Escócia.

significa o mesmo que

O Parlamento escocês se reúne em Edimburgo.

Portanto, o contexto "O Parlamento escocês se reúne em ..." é um contexto referencialmente transparente. Podemos substituir "a capital da Escócia" por "Edimburgo" sem alterar o significado. Em outras palavras, o contexto se preocupa apenas com o que o termo se refere e nada mais. É nesse sentido que o contexto é "referencialmente transparente".

Por outro lado, na frase,

Edimburgo é a capital da Escócia desde 1999.

não podemos fazer essa substituição. Se o fizéssemos, obteríamos "Edimburgo é Edimburgo desde 1999", o que é uma coisa louca de se dizer, e não transmite o mesmo significado que a frase original. Assim, parece que o contexto "Edimburgo tem sido ... desde 1999" é referencialmente opaco (o oposto de referencialmente transparente). Aparentemente, ele se preocupa com algo mais do que aquilo a que o termo se refere. O que é isso?

Coisas como "a capital da Escócia" são chamadas de termos definidos e não causam muita dor de cabeça aos lógicos e filósofos por um longo tempo. Russell e Quine os classificaram dizendo que eles não são realmente "referenciais", ou seja, é um erro pensar que os exemplos acima são usados ​​para se referir a entidades. A maneira correta de entender "Edimburgo é a capital da Escócia desde 1999" é dizer

A Escócia possui uma capital desde 1999 e essa capital é Edimburgo.

Esta frase não pode ser transformada em uma noz. Problema resolvido! O objetivo de Quine era dizer que a linguagem natural é confusa, ou pelo menos complicada, porque é conveniente para uso prático, mas filósofos e lógicos devem trazer clareza ao entendê-las da maneira correta. A transparência referencial é uma ferramenta a ser usada para trazer tanta clareza de significado .

O que tudo isso tem a ver com programação? Na verdade não muito. Como dissemos, a transparência referencial é uma ferramenta a ser usada na compreensão da linguagem, ou seja, na atribuição de significado . Christopher Strachey , que fundou o campo da semântica da linguagem de programação, o usou em seu estudo do significado. Seu artigo fundamental " Conceitos fundamentais em linguagens de programação " está disponível na web. É um jornal bonito e todos podem ler e entender. Então faça isso. Você será muito esclarecido. Ele introduz o termo "transparência referencial" neste parágrafo:

Uma das propriedades mais úteis das expressões é aquela chamada pela transparência referencial do Quine. Em essência, isso significa que, se desejamos encontrar o valor de uma expressão que contenha uma subexpressão, a única coisa que precisamos saber sobre a subexpressão é seu valor. Quaisquer outras características da subexpressão, como sua estrutura interna, o número e a natureza de seus componentes, a ordem em que são avaliadas ou a cor da tinta em que são escritas, são irrelevantes para o valor da principal expressão.

O uso de "em essência" sugere que Strachey está parafraseando-o para explicá-lo em termos simples. Programadores funcionais parecem entender este parágrafo à sua maneira. Existem 9 outras ocorrências de "transparência referencial" no artigo, mas elas não parecem se preocupar com nenhuma das outras. De fato, todo o artigo de Strachey é dedicado a explicar o significado de linguagens de programação imperativas . Hoje, porém, programadores funcionais afirmam que linguagens de programação imperativas não são referencialmente transparentes. Strachey estaria revirando seu túmulo.

Nós podemos salvar a situação. Dissemos que a linguagem natural é "confusa ou pelo menos complicada" porque é feita para ser conveniente para uso prático. Linguagens de programação são da mesma maneira. Eles são "confusos ou pelo menos complicados" porque são feitos para serem convenientes para uso prático. Isso não significa que eles precisam nos confundir. Eles apenas precisam ser entendidos da maneira certa, usando uma meta linguagem que é referencialmente transparente para que tenhamos clareza de significado. No artigo que citei, Strachey faz exatamente isso. Ele explica o significado de linguagens de programação imperativas, dividindo-as em conceitos elementares, nunca perdendo a clareza em nenhum lugar. Uma parte importante de sua análise é apontar que expressões em linguagens de programação têm dois tipos de "valores",valores r . Antes do artigo de Strachey, isso não era compreendido e a confusão reinava suprema. Hoje, a definição de C menciona-a rotineiramente e todo programador de C entende a distinção. (É difícil dizer se os programadores de outras línguas o entendem da mesma forma.

Quine e Strachey estavam preocupados com o significado das construções de linguagem que envolvem alguma forma de dependência de contexto. Por exemplo, nosso exemplo "Edimburgo é a capital da Escócia desde 1999" significa o fato de que "capital da Escócia" depende do horário em que está sendo considerada. Essa dependência de contexto é uma realidade, tanto em linguagens naturais quanto em linguagens de programação. Mesmo na programação funcional, variáveis ​​livres e vinculadas devem ser interpretadas com relação ao contexto em que aparecem. A dependência de qualquer tipo de contexto bloqueia a transparência referencial de uma maneira ou de outra. Se você tentar entender o significado dos termos sem considerar os contextos dos quais eles dependem, você acabará novamente com confusão. Quine estava preocupado com o significado da lógica modal. Ele sustentou issoa lógica modal era referencialmente opaca e deveria ser limpa, traduzindo-a em uma estrutura referencialmente transparente (por exemplo, considerando a necessidade como a disponibilidade). Ele perdeu em grande parte esse debate. Tanto lógicos quanto filósofos consideraram perfeitamente possível a semântica mundial de Kripke. Situação semelhante também reina com a programação imperativa. A dependência de estado explicada por Strachey e a dependência de loja explicada por Reynolds (de maneira semelhante à possível semântica mundial de Kripke) são perfeitamente adequadas. Programadores funcionais não conhecem muito desta pesquisa. Suas idéias sobre transparência referencial devem ser tomadas com um grande grão de sal.

[Nota adicional: Os exemplos acima ilustram que uma frase simples como "capital da Escócia" tem vários níveis de significado. Em um nível, podemos estar falando sobre a capital no momento atual. Em outro nível, poderíamos falar sobre todas as capitais possíveis que a Escócia poderia ter ao longo do tempo. Podemos "ampliar" um contexto específico e "diminuir o zoom" para abranger todos os contextos com bastante facilidade na prática normal. A eficiência da linguagem natural faz uso de nossa capacidade de fazê-lo. Linguagens de programação imperativas são eficientes da mesma maneira. Podemos usar uma variável x no lado direito de uma atribuição (o valor r ) para falar sobre seu valor em um estado específico. Ou, podemos falar sobre seu valor lque abrange todos os estados. As pessoas raramente ficam confusas com essas coisas. No entanto, eles podem ou não ser capazes de explicar com precisão todas as camadas de significado inerentes às construções da linguagem. Todas essas camadas de significado não são necessariamente "óbvias" e é uma questão de ciência estudá-las adequadamente. No entanto, a inarticulação das pessoas comuns para explicar esses significados em camadas não implica que eles estejam confusos sobre eles.]

Um "pós-escrito" separado abaixo relaciona essa discussão às preocupações da programação funcional e imperativa .

Uday Reddy
fonte
10
Obrigado, mas não considero que exista uma noção extensional "óbvia" de igualdade. Quando eu disse que a "capital da Escócia" se refere à cidade de Edimburgo, você não pensou duas vezes sobre isso. Mas quando eu comecei a falar sobre "desde 1999", você subitamente percebeu que há tempo envolvido. Portanto, a noção extensional de igualdade pode ser bastante sutil e formalizada pelos pesquisadores da linguagem de programação. As pessoas que desejam ter um entendimento perfeito da igualdade extensional precisam aprender os frutos dessa pesquisa. Pode não ser "óbvio".
precisa
5
Fantástico! Um alívio bem-vindo aos equívocos populares sobre RT, por exemplo, vinculando-o a funções . Ou definindo através da substituição de uma expressão por seu valor (como na Wikipedia) - estranhamente, já que expressões e valores são tipos diferentes de coisas. Talvez um lugar em que as pessoas erram ao considerar a RT das linguagens imperativas é assumir que esses "valores" são coisas simples como números, e não coisas mais complexas, como funções de uma loja.
Conal
13
@sclv Quanto ao impacto mais amplo da filosofia analítica na Ciência da Computação, devo dizer que a Ciência da Computação, como a conhecemos, foi fundada por Godel, Church, Kleene e Turing. Essas pessoas eram lógicas e conheciam bem os aspectos matemáticos e filosóficos da lógica, em particular as tradições de Peano, Frege, Russell, Whitehead, Carnap e Quine. Os primeiros pioneiros da ciência da computação moderna conheciam as conexões. Mas o rápido crescimento da Ciência da Computação os cortou. Precisamos voltar para eles.
Uday Reddy
5
A @sclv Logic é tradicionalmente interpretada como a ciência da consequência . Mas acho que é mais amplo. É a ciência da informação . Quine, vejo como o primeiro que trouxe à tona uma visão mais ampla. "Palavra e objeto" é uma análise do conteúdo informativo das declarações de linguagem natural. No entanto, nem filósofos nem matemáticos se interessaram ativamente pelos cálculos , o que é bastante desconcertante, dado o quão central a computação tem sido para a civilização e a ciência desde tempos imemoriais. Precisamos encontrar maneiras de interessá-los.
precisa
3
@Onal: eu adicionei uma nova resposta que amplia o seu ponto. Provavelmente estará na parte inferior da página.
Uday Reddy
134

Transparência referencial, um termo comumente usado em programação funcional, significa que, dada uma função e um valor de entrada, você sempre receberá a mesma saída. Ou seja, não há estado externo usado na função.

Aqui está um exemplo de uma função transparente referencial:

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

Com uma função transparente referencial, dada uma entrada e uma função, você pode substituí-lo por um valor em vez de chamar a função. Portanto, em vez de chamar plusOne com um parâmetro 5, podemos substituí-lo por 6.

Outro bom exemplo é a matemática em geral. Na matemática, dada uma função e um valor de entrada, ele sempre será mapeado para o mesmo valor de saída. f (x) = x + 1. Portanto, as funções em matemática são referencialmente transparentes.

Esse conceito é importante para os pesquisadores porque significa que, quando você possui uma função referencialmente transparente, ela se presta a paralelização e cache automáticos fáceis.

A transparência referencial é usada sempre em linguagens funcionais como Haskell.

-

Em contraste, existe o conceito de opacidade referencial. Isso significa o contrário. Chamar a função nem sempre produz a mesma saída.

//global G
int G = 10;

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

Outro exemplo é uma função de membro em uma linguagem de programação orientada a objetos. As funções de membro geralmente operam em suas variáveis ​​de membro e, portanto, seriam referenciais opacas. É claro que as funções de membro podem ser referencialmente transparentes.

Ainda outro exemplo é uma função que lê um arquivo de texto e imprime a saída. Esse arquivo de texto externo pode ser alterado a qualquer momento, para que a função seja referencialmente opaca.

Brian R. Bondy
fonte
1
Apenas um aviso, é possível ter um objeto totalmente referencialmente transparente, com funções-membro referencialmente transparentes. Veja okmij.org/ftp/Scheme/oop-in-fp.txt
Jonathan Arkell
1
E aqui está o código que está sendo falado nesse artigo: okmij.org/ftp/Scheme/pure-oo-system.scm
Jonathan Arkell
No caso de uma classe totalmente referencialmente transparente, você provavelmente teria todas as funções de membro estáticas.
Brian R. Bondy
13
O que você está falando aqui não é transparência referencial, embora seja comumente referido como tal. Veja as duas respostas de Uday e os comentários sobre elas. Em particular, o que você chama de "saída" não é a denotação. Se você substituísse "plusG 3" por qualquer outra expressão com o mesmo valor / denotação, você realmente obteria um programa com o mesmo significado, para que o RT se mantenha em linguagens imperativas. A expressão "3 + 10" ou "13" não tem o mesmo significado que "plusG 3", porque o significado em idiomas imperativos é uma função da "loja" (estado).
Conal
1
Acabei de ler um artigo sobre efeitos colaterais e mudança de estado e tenho uma intuição de que isso tem algo a ver com a RT. Você poderia adicionar uma observação?
Gaurav
91

Uma função referencialmente transparente é aquela que depende apenas de sua entrada.

Draemon
fonte
4
É por isso que é difícil na programação OO porque os objetos têm estado.
Kris
5
Então, é correto dizer que "referencialmente transparente" é idêntico a "determinístico" ao descrever funções? Caso contrário, qual é a diferença entre os dois termos?
Mkolfe02
1
Isso também soa como uma definição de uma função "pura".
Evgeny A.
75

[Este é um pós-escrito da minha resposta de 25 de março, em um esforço para aproximar a discussão das preocupações da programação funcional / imperativa.]

A ideia de transparência referencial dos programadores funcionais parece diferir da noção padrão de três maneiras:

  • Enquanto os filósofos / lógicos usam termos como "referência", "denotação", "designatum" e " bedeutung " (termo alemão de Frege), programadores funcionais usam o termo "valor". (Isso não é tarefa deles. Observo que Landin, Strachey e seus descendentes também usaram o termo "valor" para falar sobre referência / denotação. Pode ser apenas uma simplificação terminológica que Landin e Strachey introduziram, mas parece fazer uma grande diferença quando usado de maneira ingênua.)

  • Programadores funcionais parecem acreditar que esses "valores" existem dentro da linguagem de programação, não fora. Ao fazer isso, eles diferem dos filósofos e dos semanticistas da linguagem de programação.

  • Eles parecem acreditar que esses "valores" devem ser obtidos por avaliação.

Por exemplo, o artigo da Wikipedia sobre transparência referencial diz, nesta manhã:

Diz-se que uma expressão é referencialmente transparente se puder ser substituída por seu valor sem alterar o comportamento de um programa (em outras palavras, produzindo um programa que tenha os mesmos efeitos e saída na mesma entrada).

Isso está completamente em desacordo com o que dizem os filósofos / lógicos. Eles dizem que um contexto é referencial ou transparente referencial se uma expressão nesse contexto puder ser substituída por outra expressão que se refira à mesma coisa (uma expressão coreferencial ). Quem são esses filósofos / lógicos? Eles incluem Frege , Russell , Whitehead , Carnap , Quine , Igrejae inúmeros outros. Cada um deles é uma figura imponente. O poder intelectual combinado desses lógicos é impressionante, para dizer o mínimo. Todos eles são unânimes na posição de que referências / denotações existem fora da linguagem formal e expressões dentro da linguagem só podem falar sobre elas. Portanto, tudo o que se pode fazer dentro do idioma é substituir uma expressão por outra expressão que se refere à mesma entidade. Os próprios referentes / denotações não existem no idioma. Por que os programadores funcionais se desviam dessa tradição bem estabelecida?

Pode-se presumir que os semanticistas da linguagem de programação possam tê-los enganado. Mas eles não fizeram.

Landin :

(a) cada expressão tem uma estrutura de subexpressão de aninhamento, (b) cada subexpressão denota algo (geralmente um número, valor de verdade ou função numérica) , (c) o que uma expressão denota, ou seja, seu "valor", depende apenas da valores de suas sub-expressões, não em outras propriedades delas. [Ênfase adicionada]

Stoy :

A única coisa que importa sobre uma expressão é o seu valor, e qualquer subexpressão pode ser substituída por outra igual em valor [ênfase adicionada]. Além disso, o valor de uma expressão é, dentro de certos limites, o mesmo sempre que ocorre ".

Pássaro e Wadler :

o valor de uma expressão depende apenas dos valores de suas expressões constituintes (se houver) e essas subexpressões podem ser substituídas livremente por outras pessoas que possuam o mesmo valor [ênfase adicionada].

Assim, em retrospecto, os esforços de Landin e Strachey para simplificar a terminologia substituindo "referência" / "denotação" por "valor" podem ter sido imprudentes. Assim que alguém ouve um "valor", há uma tentação de pensar em um processo de avaliação que o conduz. É igualmente tentador pensar no que quer que a avaliação produz como o "valor", mesmo que possa ficar bem claro que essa não é a denotação. É o que eu acho que aconteceu com o conceito de "transparência referencial" aos olhos dos programadores funcionais. Mas o "valor" que estava sendo mencionado pelos primeiros semanticistas não é o resultado de uma avaliação ou o resultado de uma função ou coisa parecida. É a denotação do termo.

Depois de entendermos o chamado "valor" de uma expressão ("referência" ou "denotação" no discurso dos filósofos clássicos) como um objeto matemático / conceitual complexo, todos os tipos de possibilidades se abrem.

  • Strachey interpretou variáveis ​​em linguagens de programação imperativas como valores L , como mencionado na minha resposta de 25 de março, que é um objeto conceitual sofisticado que não tem uma representação direta na sintaxe de uma linguagem de programação.
  • Ele também interpretou comandos em linguagens como funções de estado para estado, outra instância de um objeto matemático complexo que não é um "valor" dentro da sintaxe.
  • Mesmo uma chamada de função com efeito colateral em C tem um "valor" bem definido como um transformador de estado que mapeia estados para pares de estados e valores (a chamada "mônada" na terminologia de programadores funcionais).

A relutância dos programadores funcionais em chamar essas linguagens de "referencialmente transparentes" implica apenas que eles são relutantes em admitir objetos matemáticos / conceituais complexos como "valores". Por outro lado, eles parecem perfeitamente dispostos a chamar um transformador de estado de "valor" quando é colocado em sua própria sintaxe favorita e vestido com uma palavra da moda como "mônada". Devo dizer que eles estão sendo totalmente inconsistentes, mesmo que lhes concedamos que sua idéia de "transparência referencial" tenha alguma coerência.

Um pouco de história pode lançar alguma luz sobre como essas confusões surgiram. O período entre 1962 e 1967 foi muito intenso para Christopher Strachey. Entre 1962-65, ele trabalhou em meio período como assistente de pesquisa com Maurice Wilkes para projetar e implementar a linguagem de programação que passou a ser conhecida como CPL. Essa era uma linguagem de programação imperativa, mas deveria ter também recursos poderosos da linguagem de programação funcional. Landin, que era funcionário da Strachey em sua empresa de consultoria, teve uma enorme influência na visão de Strachey das linguagens de programação. No artigo de referência de 1965 " Next 700 linguagens de programação ", Landin promove descaradamente as linguagens de programação funcional (chamando-as de denotativas).linguagens de programação imperativas como sua "antítese". Na discussão que se segue, encontramos Strachey levantando dúvidas sobre a forte posição de Landin.

... DLs formam um subconjunto de todos os idiomas. Eles são um subconjunto interessante, mas inconveniente de usar, a menos que você esteja acostumado. Precisamos deles porque, no momento , não sabemos como construir provas com linguagens que incluem imperativos e saltos. [Ênfase adicionada]

Em 1965, Strachey assumiu a posição de Leitor em Oxford e parece ter trabalhado essencialmente em tempo integral no desenvolvimento de uma teoria de imperativos e saltos. Em 1967, ele estava pronto com uma teoria, ensinada em seu curso sobre " Conceitos fundamentais em linguagens de programação " em uma escola de verão em Copenhague. As anotações das palestras deveriam ter sido publicadas, mas "infelizmente, por causa da edição dilatória, os procedimentos nunca se materializaram; como grande parte do trabalho de Strachey em Oxford, no entanto, o jornal teve uma circulação privada influente". ( Martin Campbell-Kelly )

A dificuldade de obter os escritos de Strachey poderia ter levado à propagação das confusões, com pessoas confiando em fontes secundárias e boatos. Mas agora que os " conceitos fundamentais " estão prontamente disponíveis na Web, não há necessidade de recorrer ao trabalho de adivinhação. Deveríamos ler e decidir o que Strachey queria dizer. Em particular:

  • Na seção 3.2, ele lida com "expressões" nas quais fala sobre "transparência referencial de valor-R".
  • Sua seção 3.3 lida com "comandos", onde ele fala sobre "transparência referencial de valor L".
  • Na seção 3.4.5, ele fala sobre "funções e rotinas" e declara que "qualquer partida da transparência referencial do valor-R em um contexto de valor-R deve ser eliminada decompondo a expressão em vários comandos e expressões mais simples ou, se isso acaba sendo difícil, o assunto de um comentário ".

Qualquer conversa sobre "transparência referencial" sem entender a distinção entre valores L, valores R e outros objetos complexos que preenchem o universo conceitual do programador imperativo é fundamentalmente equivocada.

Uday Reddy
fonte
10
Acho que vale a pena enfatizar que confundir essas duas noções de "valor" (avaliações versus denotações) engana os programadores funcionais em suas críticas a linguagens imperativas , onde a diferença entre as noções é grande.
Conal 31/07
8
isto é, a noção de avaliação leva à conclusão de que linguagens imperativas não são RT, enquanto a noção de denotação não.
Conal
12
Parece-me que uma vez que você realmente tenha entendido completamente a semântica denotacional de uma linguagem, ela não poderá deixar de ser referencialmente transparente. Portanto, isso equivale a dizer que o termo não é útil no que diz respeito às linguagens de programação.
21412 Tom Tomockock
20
Portanto, parece que as pessoas costumam usar um termo para significar algo materialmente diferente do que as outras pessoas queriam dizer quando usaram esse termo no passado. Para o qual eu digo: Bem-vindo ao idioma inglês.
Daniel Pratt
17
@DanielPratt: Se liberdade de efeito colateral é o que os programadores funcionais querem dizer, então por que eles chamam de "transparência referencial"? Eles podem simplesmente chamar isso de "liberdade de efeito colateral", que é uma ideia perfeitamente clara. Ninguém precisará perguntar na troca de pilhas o que significa "liberdade de efeito colateral". Onde está a necessidade de roubar termos clássicos grandiosos que ninguém parece entender?
Uday Reddy
23

Uma expressão é referencialmente transparente se puder ser substituída por seu valor, sem alterar o algoritmo, produzindo um algoritmo que tenha os mesmos efeitos e saída na mesma entrada.

CMS
fonte
18

Uma função referencialmente transparente é aquela que age como uma função matemática; dadas as mesmas entradas, sempre produzirá as mesmas saídas. Isso implica que o estado passado não é modificado e que a função não possui um estado próprio.

Barry Kelly
fonte
10

Para aqueles que precisam de uma explicação concisa, arriscarei uma (mas leia a divulgação abaixo).

A transparência referencial em uma linguagem de programação promove o raciocínio equacional - quanto mais transparência referencial você tiver, mais fácil será o raciocínio equacional. Por exemplo, com uma definição de função (pseudo),

fx = x + x,

a facilidade com que você pode (com segurança) substituir f (foo) por foo + foo no escopo desta definição, sem ter muitas restrições sobre onde é possível executar essa redução, é uma boa indicação de quanta transparência referencial sua linguagem de programação tem.

Por exemplo, se foo fosse x ++ no sentido de programação C, não seria possível executar essa redução com segurança (ou seja, se você realizasse essa redução, não terminaria com o mesmo programa em que iniciou).

Em linguagens de programação práticas, você não verá perfeita transparência referencial, mas os programadores funcionais se importam com isso mais do que a maioria (cf. Haskell, onde é um objetivo central).

(Divulgação completa: sou um programador funcional, portanto, pela resposta principal, você deve tomar essa explicação com um pouco de sal.)

chrisdornan
fonte
3
Não tenho problemas com idiomas que facilitam o raciocínio equacional. Mas eu contestaria que isso tem alguma coisa a ver com "transparência referencial", conforme definida classicamente. Em segundo lugar, como programador prático, acho que o raciocínio equacional é superestimado. O raciocínio que é importante na prática tem a ver com pré-condições, pós-condições, invariantes e abstração de dados. Para pessoas que confiam nessas técnicas de raciocínio, os efeitos colaterais não parecem importar muito. Portanto, embora eu concorde com você que os efeitos colaterais nas expressões são uma má idéia, eles não parecem representar um argumento matador.
Uday Reddy
1
@UdayReddy Só porque os programadores funcionais escolheram um método específico de discagem da transparência referencial em seus programas (eliminando efeitos colaterais e desenvolvendo uma álgebra sofisticada e poderosa de programas) ou têm alguns profissionais que provavelmente não entendem a transparência referencial e também eles pensam que sim, não significa que as linguagens de programação funcional falhem em aumentar a transparência referencial ou que os programadores de linguagem funcional e os escritores de compiladores não estão explorando esse aumento na rastreabilidade formal para muitas finalidades boas.
31712 chrisdornan
2
Chris: Uday apontou que Strachey eliminou o problema da opacidade referencial na semântica da linguagem de programação, particularmente nas linguagens imperativas. Portanto, programadores funcionais não podem estar "discando a transparência referencial em seus programas". Como um exemplo concreto, o Haskell IO não ajuda em RT exatamente porque nenhuma ajuda em RT é necessária.
Conal
2
@chrisdornan: Desculpe pelo meu primeiro comentário acima. Eu mesmo tive dificuldade em entender o que estava tentando dizer nas duas primeiras frases :-( Mas, aqui está uma explicação. Considere um cálculo de teste de dois níveis ou vários níveis. Cada operador de teste é referencialmente opaco. Na verdade, ., um operador de citação no entanto, você pode fazer o raciocínio equational dentro de cada estágio perfeitamente bem Então, cada operador referencialmente opaco configurar limites para o raciocínio equational Mas você ainda tem raciocínio equational dentro desses limites...
Uday Reddy
1
@chrisdomain: Além disso, pouquíssimas pessoas gostariam de ser puristas de transparência referenciais para banir esses operadores de teste. Esses operadores são extremamente úteis. Programar sem eles executando a preparação manualmente seria tedioso, propenso a erros e feio. E, fazer a encenação manualmente não compraria mais raciocínio equacional do que você tinha anteriormente. Portanto, proibir bons dispositivos de programação na busca purista do raciocínio equacional seria como cortar o nariz para irritar o rosto.
Uday Reddy
8

Se você está interessado na etimologia (por exemplo, por que esse conceito tem esse nome específico), dê uma olhada no meu blog sobre o assunto. A terminologia vem do filósofo / lógico Quine.

Andrew Birkett
fonte
4
  1. A semântica denotacional é baseada em linguagens de modelagem, construindo domínios que constituem valores denotáveis .
  2. Programadores Funcionais usam o termo valor para descrever a convergência de uma computação com base nas regras de reescrita da linguagem, ie. sua semântica operacional.

Em 1, há uma clareza de dois idiomas em questão:

  • aquele que está sendo modelado, a linguagem do objeto
  • a linguagem da modelagem, a meta linguagem

Em 2, graças à proximidade do objeto e das metalinguagens, eles podem ser confundidos.

Como implementador de linguagem, acho que preciso lembrar constantemente dessa distinção.

Reddy, posso parafrasear você assim :-)

Nos contextos de programação funcional e semântica, o termo Transparência Referencial não é referencialmente transparente.

Anuradha
fonte
1
Ha ha. Obrigada pelo esclarecimento. O problema também é que os programadores funcionais agem como se tivessem uma noção geral de "transparência referencial" aplicável a todas as linguagens de programação . Mas isso depende da noção de "valor", que pode ou não fazer sentido para outras línguas. Para reivindicar uma teoria geral da "transparência referencial", eles precisam produzir um "valor" da teoria geral. Isso está faltando até agora.
Uday Reddy
4

Espero que a seguinte resposta adicione e qualifique as controversas 1ª e 3ª respostas.

Vamos admitir que uma expressão denota ou se refere a algum referente. No entanto, uma pergunta é se esses referentes podem ser codificados isomorficamente como parte das próprias expressões, chamando essas expressões de "valores". Por exemplo, valores numéricos literais são um subconjunto do conjunto de expressões aritméticas, valores verdadeiros são um subconjunto do conjunto de expressões booleanas, etc. A idéia é avaliar uma expressão em seu valor (se houver). Portanto, a palavra 'valor' pode se referir a uma denotação ou a um elemento distinto do conjunto de expressões. Mas se houver um isomorfismo (uma bijeção) entre o referente e o valor, podemos dizer que eles são a mesma coisa. (Dito isto, é preciso ter cuidado ao definir os referentes e o isomorfismo, conforme comprovado pelo campo da semântica denotacional. Para colocar um exemplo mencionado pelas respostas à 3ª resposta,data Nat = Zero | Suc Nat não corresponde conforme o esperado ao conjunto de números naturais.)

Vamos escrever E[·]para uma expressão com um buraco, também conhecido em alguns setores como um 'contexto'. Dois exemplos de contexto para expressões do tipo C são [·]+1e [·]++.

Vamos escrever [[·]]para a função que pega uma expressão (sem buraco) e entrega seu significado (referente, denotação etc.) em algum universo que fornece significado. (Estou emprestando uma notação do campo da semântica denotacional.)

Vamos adaptar formalmente a definição de Quine da seguinte forma: um contexto E[·] é referencialmente transparente se houver duas expressões E1e E2(não existem buracos) de tal modo que [[E1]] = [[E2]](ou seja, as expressões denotem / se refiram ao mesmo referente), então é o caso que [[E[E1]]] = [[E[E2]]](ou seja, preencher -no buraco com um E1ou E2resulta em expressões que também denotam o mesmo referente).

A regra de Leibniz de substituir iguais por iguais é normalmente expressa como 'se E1 = E2assim for E[E1] = E[E2]', o que diz que E[·]é uma função. Uma função (ou, nesse caso, um programa que calcula a função) é um mapeamento de uma origem para um destino, para que haja no máximo um elemento de destino para cada elemento de origem. Funções não determinísticas são desnômeros, são relações, funções que fornecem conjuntos, etc. Se na regra de Leibniz a igualdade =é denotacional, os colchetes duplos são simplesmente tomados como garantidos e elididos. Portanto, um contexto referencialmente transparente é uma função. E a regra de Leibniz é o principal ingrediente do raciocínio equacional; portanto, o raciocínio equacional está definitivamente relacionado à transparência referencial.

Embora [[·]]seja uma função de expressões para denotações, pode ser uma função de expressões para 'valores' entendidos como um subconjunto restrito de expressões e [[·]]pode ser entendida como avaliação.

Agora, se E1é uma expressão e E2é um valor, temos o que eu acho que significa a maioria das pessoas ao definir transparência referencial em termos de expressões, valores e avaliação. Mas, como ilustrado pelas 1ª e 3ª respostas desta página, esta é uma definição imprecisa.

O problema com contextos como [·]++não é o efeito colateral, mas seu valor não é definido em C isomorficamente ao seu significado. Funções não são valores (bem, ponteiros para funções são), enquanto nas linguagens de programação funcionais são. Landin, Strachey e os pioneiros da semântica denotacional foram bastante inteligentes ao usar mundos funcionais para fornecer significado.

Por imperativo C-como línguas nós podemos (aproximadamente) fornecer semântica de expressões usando a função [[·]] : Expression -> (State -> State x Value).

Valueé um subconjunto de Expression. Statecontém pares (identificador, valor). A função semântica pega uma expressão e entrega como significado uma função do estado atual para o par com o estado atualizado e um valor. Por exemplo, [[x]]é a função do estado atual para o par cujo primeiro componente é o estado atual e cujo segundo componente é o valor de x. Por outro lado, [[x++]]é a função do estado atual para o par cujo primeiro componente é um estado no qual o valor de x é incrementado e cujo segundo componente é esse mesmo valor. Nesse sentido, o contexto [·]++é referencialmente transparente se satisfizer a definição dada acima.

Acho que os programadores funcionais têm o direito de usar a transparência referencial no sentido de que se recuperam naturalmente [[·]]como uma função das expressões aos valores. Funções são valores de primeira classe e o estado também pode ser um valor, não uma denotação. A mônada do estado é (em parte) um mecanismo limpo para passar (ou encadear) o estado.


fonte
Presumivelmente, as respostas "1º" e "3º" são as respostas de "25 de março" e "pós-escrito" de UdayReddy, respectivamente. Os ordinais não são uma boa maneira de se referir às respostas no SO. Não apenas os votos e as aceitações podem mudar ao longo do tempo, mas há vários pedidos selecionáveis.
philipxy
2

Observe que esse conceito de "significado" é algo que acontece na mente do observador. Assim, a mesma "referência" pode significar coisas diferentes para pessoas diferentes. Por exemplo, temos uma página de desambiguação de Edimburgo na Wikipedia.

Uma questão relacionada que pode aparecer no contexto da programação pode ser o polimorfismo.

E talvez devêssemos ter um nome para o caso especial de polimorfismo (ou talvez até vazamento), onde, para nossos propósitos, os diferentes casos polimórficos são semanticamente equivalentes (em vez de apenas serem semelhantes. Por exemplo, o número 1 - que pode ser representado usando um tipo inteiro, complexo ou qualquer outro tipo - pode ser tratado polimorficamente).

rdm
fonte
0

Achei a definição de transparência referencial no livro " Estrutura e implementação de programas de computador " (o Livro do assistente) útil porque é complementada por uma explicação de como a transparência referencial é violada pela introdução da operação de atribuição . Confira o seguinte slide deck que fiz sobre o assunto: https://www.slideshare.net/pjschwarz/introducing-assignment-invalidates-the-substitution-model-of-evaluation-and-violates-referential-transparency-as- explicado-em-sicp-o-assistente-livro

Philip Schwarz
fonte
0

A transparência referencial pode ser simplesmente declarada como:

  • Uma expressão sempre avaliando o mesmo resultado em qualquer contexto [1] ,
  • Uma função, se receber os mesmos parâmetros duas vezes, deve produzir o mesmo resultado duas vezes [2] .

Por exemplo, a linguagem de programação Haskell é uma linguagem funcional pura; o que significa que é referencialmente transparente.

lata
fonte