¿Qué es la transparencia referencial?

285

¿Qué significa el término transparencia referencial ? Lo escuché descrito como "significa que puedes reemplazar iguales por iguales", pero esto parece una explicación inadecuada.

Claudiu
fuente
1
wow me pregunto por qué el repentino aumento de la popularidad de esta pregunta ...
Claudiu
1
@claudia: No puedo decir con certeza, pero r / haskell se enteró y muchos sintieron que Uday era, aunque bastante exacto, tomando un poco de burla en la comunidad.
efrey
66
@efrey Una burla, tal vez lo fue. Pero, cuando los programadores funcionales derriban lenguajes de programación imperativos y lenguajes funcionales de efectos secundarios (como Lisp y ML) alegando que no son referencialmente transparentes, ¿no están tomando el pelo? ¿No deberían al menos tener sus datos correctos antes de hacerlo?
Uday Reddy
2
@Claudiu Lo he estado publicando en Haskell Reddit y Conal lo ha estado tuiteando. La discusión me pareció interesante y pensé que merecía una discusión más amplia. Llamé la atención a la burla de Uday para estimular una discusión. Estoy de acuerdo en que nosotros, los FPers, a veces podemos ser complacientes y necesitamos un buen producto, ¡bien hecho a Uday por proporcionarlo!
chrisdornan
77
@efrey. De hecho, es por eso que elegí citar a Bird y Wadler (¿semánticos?) En mi segunda publicación. Las personas conocedoras saben que la concepción popular de la transparencia referencial es vaga y posiblemente incoherente. Pero nunca se ha explicado a la comunidad de programación correctamente. Espero que mi escritura aquí haga una diferencia.
Uday Reddy

Respuestas:

362

El término "transparencia referencial" proviene de la filosofía analítica , la rama de la filosofía que analiza construcciones del lenguaje natural, declaraciones y argumentos basados ​​en los métodos de la lógica y las matemáticas. En otras palabras, es el tema más cercano fuera de la informática a lo que llamamos semántica del lenguaje de programación . El filósofo Willard Quine fue responsable de iniciar el concepto de transparencia referencial, pero también estuvo implícito en los enfoques de Bertrand Russell y Alfred Whitehead.

En esencia, la "transparencia referencial" es una idea muy simple y clara. El término "referente" se utiliza en filosofía analítica para hablar sobre lo que se refiere a una expresión . Es más o menos lo que queremos decir con "significado" o "denotación" en la semántica del lenguaje de programación. Usando el ejemplo de Andrew Birkett ( publicación de blog ), el término "la capital de Escocia" se refiere a la ciudad de Edimburgo. Ese es un ejemplo directo de un "referente".

Un contexto en una oración es "referencialmente transparente" si reemplazar un término en ese contexto por otro término que se refiera a la misma entidad no altera el significado. Por ejemplo

El Parlamento escocés se reúne en la capital de Escocia.

significa lo mismo que

El Parlamento escocés se reúne en Edimburgo.

Entonces, el contexto "El Parlamento escocés se reúne en ..." es un contexto referencialmente transparente. Podemos reemplazar "la capital de Escocia" con "Edimburgo" sin alterar el significado. En otras palabras, al contexto solo le importa a qué se refiere el término y nada más. Ese es el sentido en el que el contexto es "referencialmente transparente".

Por otro lado, en la oración,

Edimburgo ha sido la capital de Escocia desde 1999.

No podemos hacer tal reemplazo. Si lo hiciéramos, obtendríamos "Edimburgo ha sido Edimburgo desde 1999", lo cual es una locura que decir, y no transmite el mismo significado que la oración original. Entonces, parece que el contexto "Edimburgo ha sido ... desde 1999" es referencialmente opaco (lo opuesto a referencialmente transparente). Aparentemente le importa algo más de lo que se refiere el término. ¿Qué es?

Cosas como "la capital de Escocia" se llaman términos definidos y no le dieron mucho dolor de cabeza a los lógicos y filósofos durante mucho tiempo. Russell y Quine los resolvieron diciendo que en realidad no son "referenciales", es decir, es un error pensar que los ejemplos anteriores se usan para referirse a entidades. La forma correcta de entender "Edimburgo ha sido la capital de Escocia desde 1999" es decir

Escocia ha tenido una capital desde 1999 y esa capital es Edimburgo.

Esta oración no puede transformarse en una nuez. ¡Problema resuelto! El punto de Quine era decir que el lenguaje natural es desordenado, o al menos complicado, porque está hecho para ser conveniente para el uso práctico, pero los filósofos y los lógicos deben aportar claridad al comprenderlos de la manera correcta. La transparencia referencial es una herramienta que se utiliza para aportar tanta claridad de significado. .

¿Qué tiene que ver todo esto con la programación? No mucho, en realidad. Como dijimos, la transparencia referencial es una herramienta para ser utilizada en la comprensión del lenguaje, es decir, en la asignación de significado . Christopher Strachey , quien fundó el campo de la semántica del lenguaje de programación, lo usó en su estudio del significado. Su documento fundamental " Conceptos fundamentales en lenguajes de programación " está disponible en la web. Es un papel hermoso y todos pueden leerlo y comprenderlo. Entonces, por favor hazlo. Estarás muy iluminado. Introduce el término "transparencia referencial" en este párrafo:

Una de las propiedades más útiles de las expresiones es la llamada por la transparencia referencial de Quine. En esencia, esto significa que si deseamos encontrar el valor de una expresión que contiene una sub-expresión, lo único que necesitamos saber sobre la sub-expresión es su valor. Cualquier otra característica de la subexpresión, como su estructura interna, el número y la naturaleza de sus componentes, el orden en que se evalúan o el color de la tinta en la que están escritos, son irrelevantes para el valor del principal expresión.

El uso de "en esencia" sugiere que Strachey lo está parafraseando para explicarlo en términos simples. Los programadores funcionales parecen entender este párrafo a su manera. Hay otros 9 casos de "transparencia referencial" en el documento, pero no parecen preocuparse por ninguno de los otros. De hecho, todo el artículo de Strachey está dedicado a explicar el significado de los lenguajes de programación imperativos . Pero, hoy, los programadores funcionales afirman que los lenguajes de programación imperativos no son referencialmente transparentes. Strachey se estaría revolviendo en su tumba.

Podemos salvar la situación. Dijimos que el lenguaje natural es "desordenado, o al menos complicado" porque está hecho para ser conveniente para el uso práctico. Los lenguajes de programación son de la misma manera. Son "desordenados, o al menos complicados" porque están hechos para ser convenientes para el uso práctico. Eso no significa que tengan que confundirnos. Solo deben entenderse de la manera correcta, utilizando un metalenguaje que sea referencialmente transparente para que tengamos claridad de significado. En el artículo que cité, Strachey hace exactamente eso. Explica el significado de los lenguajes de programación imperativos desglosándolos en conceptos elementales, sin perder claridad en ningún lado. Una parte importante de su análisis es señalar que las expresiones en los lenguajes de programación tienen dos tipos de "valores",valores r . Antes del artículo de Strachey, esto no se entendía y la confusión reinaba supremamente. Hoy, la definición de C lo menciona rutinariamente y cada programador de C comprende la distinción. (Es difícil decir si los programadores en otros idiomas lo entienden igualmente bien).

Tanto Quine como Strachey estaban preocupados por el significado de las construcciones del lenguaje que implican alguna forma de dependencia del contexto. Por ejemplo, nuestro ejemplo "Edimburgo ha sido la capital de Escocia desde 1999" significa el hecho de que la "capital de Escocia" depende del momento en que se está considerando. Tal dependencia del contexto es una realidad, tanto en lenguajes naturales como en lenguajes de programación. Incluso en la programación funcional, las variables libres y enlazadas deben interpretarse con respecto al contexto en el que aparecen. La dependencia del contexto de cualquier tipo bloquea la transparencia referencial de una forma u otra. Si intentas comprender el significado de los términos sin tener en cuenta los contextos de los que dependen, nuevamente terminarás confundido. A Quine le preocupaba el significado de la lógica modal. Sostuvo quela lógica modal era referencialmente opaca y debería limpiarse traduciéndola a un marco referencialmente transparente (por ejemplo, considerando la necesidad como demostrabilidad). En gran medida perdió este debate. Tanto los lógicos como los filósofos encontraron que la posible semántica mundial de Kripke era perfectamente adecuada. Una situación similar también reina con la programación imperativa. La dependencia del estado explicada por Strachey y la dependencia de la tienda explicada por Reynolds (de manera similar a la posible semántica mundial de Kripke) son perfectamente adecuadas. Los programadores funcionales no saben mucho de esta investigación. Sus ideas sobre la transparencia referencial deben tomarse con un gran grano de sal.

[Nota adicional: Los ejemplos anteriores ilustran que una frase simple como "capital de Escocia" tiene múltiples niveles de significado. En un nivel, podríamos estar hablando de la capital en el momento actual. En otro nivel, podríamos hablar de todas las capitales posibles que Escocia podría haber tenido a lo largo del tiempo. Podemos "acercarnos" a un contexto particular y "alejar" para abarcar todos los contextos con bastante facilidad en la práctica normal. La eficiencia del lenguaje natural hace uso de nuestra capacidad para hacerlo. Los lenguajes de programación imperativos son eficientes de la misma manera. Podemos usar una variable x en el lado derecho de una asignación (el valor r ) para hablar sobre su valor en un estado particular. O podríamos hablar sobre su valor lque abarca todos los estados Las personas rara vez se confunden con tales cosas. Sin embargo, pueden o no ser capaces de explicar con precisión todas las capas de significado inherentes a las construcciones del lenguaje. Todas esas capas de significado no son necesariamente 'obvias' y es una cuestión científica estudiarlas adecuadamente. Sin embargo, la falta de articulación de la gente común para explicar dichos significados en capas no implica que estén confundidos acerca de ellos.]

Un "postscript" separado a continuación relaciona esta discusión con las preocupaciones de la programación funcional e imperativa .

Uday Reddy
fuente
10
Gracias, pero no sostengo que haya una noción extensional 'obvia' de igualdad. Cuando dije que la "capital de Escocia" se refiere a la ciudad de Edimburgo, no lo pensaste dos veces. Pero cuando comencé a hablar de "desde 1999", de repente te das cuenta de que hay tiempo involucrado. Entonces, la noción extensional de igualdad puede ser bastante sutil y está formalizada por investigadores de lenguaje de programación. Las personas que desean tener una comprensión perfecta de la igualdad extensional necesitan aprender los frutos de esa investigación. Puede no ser en absoluto "obvio".
Uday Reddy
55
¡Fantástico! Un alivio bienvenido a los conceptos erróneos populares sobre RT, por ejemplo, vincularlo a las funciones . O definir mediante la sustitución de una expresión con su valor (como en Wikipedia), curiosamente ya que las expresiones y los valores son diferentes tipos de cosas. Quizás un lugar donde las personas se equivocan al considerar la RT-ness de los lenguajes imperativos es asumir que estos "valores" son cosas simples como números en lugar de cosas más complejas como funciones de una tienda.
Conal
13
@sclv En cuanto al impacto más amplio de la filosofía analítica en la informática, debo decir que la informática, tal como la conocemos, fue fundada por Godel, Church, Kleene y Turing. Estas personas eran lógicos y estaban bien versados ​​en los aspectos matemáticos y filosóficos de la lógica, en particular las tradiciones de Peano, Frege, Russell, Whitehead, Carnap y Quine. Los primeros pioneros de la informática moderna conocían las conexiones. Pero el rápido crecimiento de la informática lo ha cortado. Necesitamos volver a ellos.
Uday Reddy
55
@sclv La lógica se interpreta tradicionalmente como la ciencia de la consecuencia . Pero creo que es más amplio. Es la ciencia de la información . Quine, veo como el primero que presentó la visión más amplia. "Palabra y objeto" es un análisis del contenido de información de las declaraciones del lenguaje natural. Sin embargo, ni los filósofos ni los matemáticos han tenido un interés activo en los cálculos , lo cual es bastante desconcertante, dada la centralidad que ha tenido la computación para la civilización y la ciencia desde tiempos inmemoriales. Necesitamos encontrar formas de interesarlos.
Uday Reddy
3
@Conal: he agregado una nueva respuesta que amplifica su punto. Probablemente estará al final de la página.
Uday Reddy
134

Transparencia referencial, un término comúnmente utilizado en la programación funcional, significa que dada una función y un valor de entrada, siempre recibirá la misma salida. Es decir, no se utiliza ningún estado externo en la función.

Aquí hay un ejemplo de una función transparente referencial:

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

Con una función transparente referencial, dada una entrada y una función, puede reemplazarla con un valor en lugar de llamar a la función. Entonces, en lugar de llamar a plusOne con un parámetro de 5, podríamos reemplazarlo con 6.

Otro buen ejemplo es la matemática en general. En matemáticas, dada una función y un valor de entrada, siempre se asignará al mismo valor de salida. f (x) = x + 1. Por lo tanto, las funciones en matemáticas son referencialmente transparentes.

Este concepto es importante para los investigadores porque significa que cuando se tiene una función referencialmente transparente, se presta a una fácil paralelización y almacenamiento en caché.

La transparencia referencial se usa siempre en lenguajes funcionales como Haskell.

-

En contraste, existe el concepto de opacidad referencial. Esto significa lo contrario. Llamar a la función puede no siempre producir la misma salida.

//global G
int G = 10;

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

Otro ejemplo, es una función miembro en un lenguaje de programación orientado a objetos. Las funciones miembro comúnmente operan en sus variables miembro y por lo tanto serían referenciales opacas. Sin embargo, las funciones de los miembros pueden, por supuesto, ser referencialmente transparentes.

Otro ejemplo más es una función que lee un archivo de texto e imprime el resultado. Este archivo de texto externo podría cambiar en cualquier momento, por lo que la función sería referencialmente opaca.

Brian R. Bondy
fuente
1
Solo un aviso, es posible tener un objeto transparente de referencia completa, con funciones miembro transparente de referencia. Ver okmij.org/ftp/Scheme/oop-in-fp.txt
Jonathan Arkell
1
Y aquí está el código del que se habla en ese artículo: okmij.org/ftp/Scheme/pure-oo-system.scm
Jonathan Arkell
En el caso de una clase transparente de referencia completa, probablemente tendría todas las funciones miembro estáticas.
Brian R. Bondy
13
De lo que estás hablando aquí no es de la transparencia referencial, aunque comúnmente se conoce como tal. Vea las dos respuestas de Uday y los comentarios sobre ellas. En particular, lo que llama la "salida" no es la denotación. Si reemplaza "plusG 3" con cualquier otra expresión que tenga el mismo valor / denotación, de hecho obtendría un programa con el mismo significado, por lo que RT se mantiene en lenguajes imperativos. La expresión "3 + 10" o "13" no tiene el mismo significado que "plusG 3", porque el significado en los idiomas imperativos es una función del "almacén" (estado).
Conal
1
Acabo de leer un artículo sobre los efectos secundarios y el cambio de estado y tengo la intuición de que tiene algo que ver con la RT. ¿Podría por favor agregar una nota?
Gaurav
91

Una función referencialmente transparente es aquella que solo depende de su entrada.

Draemon
fuente
44
Es por eso que es difícil en la programación OO porque los objetos tienen estado.
Kris
55
Entonces, ¿es correcto decir que "referencialmente transparente" es idéntico a "determinista" al describir funciones? Si no, ¿cuál es la diferencia entre los dos términos?
mwolfe02
1
Esto también suena como una definición de una función "pura".
Evgeny A.
75

[Esta es una posdata a mi respuesta del 25 de marzo, en un esfuerzo por acercar la discusión a las preocupaciones de la programación funcional / imperativa.]

La idea de los programadores funcionales de transparencia referencial parece diferir de la noción estándar en tres formas:

  • Mientras que los filósofos / lógicos usan términos como "referencia", "denotación", "designatum" y " bedeutung " (término alemán de Frege), los programadores funcionales usan el término "valor". (Esto no es del todo de ellos. Noto que Landin, Strachey y sus descendientes también usaron el término "valor" para hablar de referencia / denotación. Puede ser solo una simplificación terminológica que introdujeron Landin y Strachey, pero parece hacer una gran diferencia cuando se usa de manera ingenua.)

  • Los programadores funcionales parecen creer que estos "valores" existen dentro del lenguaje de programación, no fuera. Al hacer esto, difieren tanto de los filósofos como de los semánticos del lenguaje de programación.

  • Parecen creer que se supone que estos "valores" se obtienen por evaluación.

Por ejemplo, el artículo de Wikipedia sobre transparencia referencial dice, esta mañana:

Se dice que una expresión es referencialmente transparente si puede reemplazarse por su valor sin cambiar el comportamiento de un programa (en otras palabras, producir un programa que tenga los mismos efectos y resultados en la misma entrada).

Esto está completamente en desacuerdo con lo que dicen los filósofos / lógicos. Dicen que un contexto es referencial o referencialmente transparente si una expresión en ese contexto puede ser reemplazada por otra expresión que se refiera a la misma cosa (una expresión de referencia central ). ¿Quiénes son estos filósofos / lógicos? Incluyen a Frege , Russell , Whitehead , Carnap , Quine , Churche innumerables otros. Cada uno de ellos es una figura imponente. El poder intelectual combinado de estos lógicos es devastador, por decir lo menos. Todos ellos son unánimes en la posición de que los referentes / denotaciones existen fuera del lenguaje formal y las expresiones dentro del lenguaje solo pueden hablar sobre ellos. Entonces, todo lo que uno puede hacer dentro del lenguaje es reemplazar una expresión por otra expresión que se refiera a la misma entidad. Los referentes / denotaciones en sí mismos no existen dentro del lenguaje. ¿Por qué los programadores funcionales se desvían de esta tradición bien establecida?

Se podría suponer que los semánticos del lenguaje de programación podrían haberlos engañado. Pero no lo hicieron.

Landin :

(a) cada expresión tiene una estructura de subexpresión anidada, (b) cada subexpresión denota algo (generalmente un número, valor de verdad o función numérica) , (c) lo que denota una expresión, es decir, su "valor", depende solo del valores de sus subexpresiones, no en otras propiedades de ellos. [Énfasis añadido]

Stoy :

Lo único que importa sobre una expresión es su valor, y cualquier subexpresión puede ser reemplazada por cualquier otro valor igual [énfasis agregado]. Además, el valor de una expresión es, dentro de ciertos límites, el mismo cada vez que ocurre ".

Pájaro y Wadler :

el valor de una expresión depende solo de los valores de sus expresiones constituyentes (si las hay) y estas subexpresiones pueden ser reemplazadas libremente por otras que posean el mismo valor [énfasis agregado].

Entonces, en retrospectiva, los esfuerzos de Landin y Strachey para simplificar la terminología mediante la sustitución de "referencia" / "denotación" con "valor" podrían haber sido perjudiciales. Tan pronto como uno escucha un "valor", existe la tentación de pensar en un proceso de evaluación que lo conduzca. Es igualmente tentador pensar en lo que sea que la evaluación produzca como el "valor", aunque podría estar bastante claro que esa no es la denotación. Eso es lo que deduzco que sucedió con el concepto de "transparencia referencial" a los ojos de los programadores funcionales. Pero el "valor" del que hablaban los primeros semánticos no es el resultado de una evaluación o el resultado de una función o algo por el estilo. Es la denotación del término.

Una vez que entendemos el llamado "valor" de una expresión ("referencia" o "denotación" en el discurso de los filósofos clásicos) como un objeto matemático / conceptual complejo, se abren todo tipo de posibilidades.

  • Strachey interpretó las variables en lenguajes de programación imperativos como valores L , como se menciona en mi respuesta del 25 de marzo, que es un objeto conceptual sofisticado que no tiene una representación directa dentro de la sintaxis de un lenguaje de programación.
  • También interpretó comandos en dichos lenguajes como funciones de estado a estado, otra instancia de un objeto matemático complejo que no es un "valor" dentro de la sintaxis.
  • Incluso una llamada de función de efecto secundario en C tiene un "valor" bien definido como un transformador de estado que asigna estados a pares de estados y valores (la llamada "mónada" en la terminología de los programadores funcionales).

La renuencia de los programadores funcionales a llamar a estos lenguajes "referencialmente transparentes" simplemente implica que son reacios a admitir objetos matemáticos / conceptuales complejos como "valores". Por otro lado, parecen perfectamente dispuestos a llamar a un transformador de estado un "valor" cuando se coloca en su propia sintaxis favorita y se viste con una palabra de moda como "mónada". Tengo que decir que están siendo completamente inconsistentes, incluso si les garantizamos que su idea de "transparencia referencial" tiene cierta coherencia.

Un poco de historia podría arrojar algo de luz sobre cómo surgieron estas confusiones. El período entre 1962 y 1967 fue muy intenso para Christopher Strachey. Entre 1962 y 1965, tomó un trabajo de medio tiempo como asistente de investigación con Maurice Wilkes para diseñar e implementar el lenguaje de programación que se conoció como CPL. Este era un lenguaje de programación imperativo, pero también debía tener potentes capacidades funcionales de lenguaje de programación. Landin, que era empleado de Strachey en su empresa de consultoría, tuvo una gran influencia en la visión de Strachey de los lenguajes de programación. En el histórico documento de 1965 "Los siguientes 700 lenguajes de programación ", Landin promueve descaradamente los lenguajes de programación funcionales (llamándolos denotativoslenguajes) y describe los lenguajes de programación imperativos como su "antítesis". En la discusión subsiguiente, encontramos a Strachey planteando dudas sobre la fuerte posición de Landin.

... Los DL forman un subconjunto de todos los idiomas. Son un subconjunto interesante, pero que es incómodo de usar a menos que esté acostumbrado. Los necesitamos porque por el momento no sabemos cómo construir pruebas con lenguajes que incluyan imperativos y saltos. [Énfasis añadido]

En 1965, Strachey tomó la posición de lector en Oxford y parece haber trabajado esencialmente a tiempo completo en el desarrollo de una teoría de los imperativos y los saltos. En 1967, estaba listo con una teoría, que enseñó en su curso sobre " Conceptos fundamentales en lenguajes de programación " en una escuela de verano de Copenhague. Se suponía que las notas de la conferencia debían publicarse, pero "desafortunadamente, debido a la edición dilatoria, los procedimientos nunca se materializaron; sin embargo, como gran parte del trabajo de Strachey en Oxford, el periódico tuvo una circulación privada influyente". ( Martin Campbell-Kelly )

La dificultad de obtener los escritos de Strachey podría haber llevado a la propagación de las confusiones, con personas que dependen de fuentes secundarias y rumores. Pero, ahora que los " Conceptos fundamentales " están fácilmente disponibles en la web, no hay necesidad de recurrir a adivinar el trabajo. Deberíamos leerlo y decidir qué quería decir Strachey. En particular:

  • En la sección 3.2, se ocupa de "expresiones" donde habla de "transparencia referencial de valor R".
  • Su sección 3.3 trata de "comandos" donde habla de "transparencia referencial de valor L".
  • En la sección 3.4.5, habla sobre "funciones y rutinas" y declara que "cualquier desviación de la transparencia referencial del valor R en un contexto de valor R debería eliminarse descomponiendo la expresión en varios comandos y expresiones más simples, o, si esto resulta ser difícil, el tema de un comentario ".

Cualquier conversación sobre "transparencia referencial" sin comprender la distinción entre valores L, valores R y otros objetos complejos que pueblan el universo conceptual del programador imperativo es fundamentalmente errónea.

Uday Reddy
fuente
10
Creo que vale la pena enfatizar que confundir estas dos nociones de "valor" (evaluaciones versus denotaciones) engaña a los programadores funcionales en su crítica de los lenguajes imperativos , donde la brecha entre las nociones es grande.
Conal
8
es decir, la noción de evaluación lleva a la conclusión de que los lenguajes imperativos no son RT, mientras que la noción de denotación no lo hace.
Conal
12
Me parece que una vez que realmente ha logrado definir completamente la semántica denotativa de un lenguaje, no puede evitar ser referencialmente transparente. Esto parece equivalente a decir que el término no es útil con respecto a los lenguajes de programación.
Tom Crockett
20
Entonces parece que la gente tiene la costumbre de usar un término para significar algo materialmente diferente de lo que otras personas querían decir cuando usaron ese término en el pasado. A lo que digo: Bienvenido al idioma inglés.
Daniel Pratt
17
@DanielPratt: Si la libertad de efectos secundarios es lo que quieren decir los programadores funcionales, ¿por qué lo llaman "transparencia referencial"? Pueden llamarlo "libertad de efectos secundarios", que es una idea perfectamente clara. Nadie tendrá que preguntar en stackexchange qué significa "libertad de efectos secundarios". ¿Dónde está la necesidad de encontrar términos clásicos grandiosos que nadie parece entender?
Uday Reddy
23

Una expresión es referencialmente transparente si se puede reemplazar con su valor, sin cambiar el algoritmo, produciendo un algoritmo que tiene los mismos efectos y resultados en la misma entrada.

CMS
fuente
18

Una función referencialmente transparente es aquella que actúa como una función matemática; Dadas las mismas entradas, siempre producirá las mismas salidas. Implica que el estado pasado no se modifica y que la función no tiene estado propio.

Barry Kelly
fuente
10

Para aquellos que necesitan una explicación concisa, voy a arriesgar una (pero lea la divulgación a continuación).

La transparencia referencial en un lenguaje de programación promueve el razonamiento equitativo: cuanta más transparencia referencial tenga, más fácil será hacer un razonamiento equitativo. Por ejemplo, con una definición de (pseudo) función,

fx = x + x,

la facilidad con la que puede reemplazar (con seguridad) f (foo) con foo + foo en el alcance de esta definición, sin tener demasiadas restricciones sobre dónde puede realizar esta reducción, es una buena indicación de cuánta transparencia referencial tiene su lenguaje de programación tiene.

Por ejemplo, si foo fuera x ++ en el sentido de la programación en C, entonces no podría realizar esta reducción de forma segura (es decir, si realizara esta reducción no terminaría con el mismo programa con el que comenzó).

En los lenguajes de programación prácticos no verá una transparencia referencial perfecta, pero a los programadores funcionales les importa más que a la mayoría (cf Haskell, donde es un objetivo central).

(Divulgación completa: soy un programador funcional, por lo que, según la respuesta principal, debería tomar esta explicación con un grano de sal).

chrisdornan
fuente
3
No tengo ningún problema con los idiomas que facilitan el razonamiento equitativo. Pero diría que tiene algo que ver con la "transparencia referencial" como se define clásicamente. En segundo lugar, como programador práctico, creo que el razonamiento equitativo está sobrevalorado. El razonamiento que es importante en la práctica tiene que ver con condiciones previas, condiciones posteriores, invariantes y abstracción de datos. Para las personas que confían en tales técnicas de razonamiento, los efectos secundarios no parecen importar mucho. Entonces, si bien estoy de acuerdo con usted en que los efectos secundarios en las expresiones son una mala idea, no parecen representar un argumento asesino.
Uday Reddy
1
@UdayReddy Solo porque los programadores funcionales han elegido un método particular para aumentar la transparencia referencial en sus programas (eliminando los efectos secundarios y desarrollando un álgebra sofisticada y poderosa de programas), o tienen algunos profesionales que probablemente no entienden la transparencia referencial, así como piensan que lo hacen, no significa que los lenguajes de programación funcional no estén logrando aumentar la transparencia referencial o que los programadores de lenguaje funcional y los escritores de compiladores no estén explotando este aumento en la trazabilidad formal para muchos fines buenos.
chrisdornan
2
Chris: Uday señaló que Strachey eliminó el problema de la opacidad referencial en la semántica del lenguaje de programación, particularmente para los lenguajes imperativos. Por lo tanto, los programadores funcionales no pueden estar "marcando la transparencia referencial en sus programas". Como ejemplo concreto, Haskell IO no ayuda con RT exactamente porque no se necesita ayuda de RT.
Conal
2
@chrisdornan: Perdón por mi primer comentario arriba. Yo mismo tuve dificultades para entender lo que estaba tratando de decir en las primeras dos oraciones :-( Pero, aquí hay una explicación. Considere un cálculo de estadificación de dos niveles o de niveles múltiples. Cada operador de estadificación es referencialmente opaco. De hecho, es ., un operador de cotización Sin embargo, se puede hacer un razonamiento ecuacional dentro de cada etapa perfectamente bien lo tanto, cada operador referencialmente opaca estableció límites para el razonamiento ecuacional, pero todavía tiene el razonamiento ecuacional dentro de esos límites...
Uday Reddy
1
@chrisdomain: Además, muy pocas personas desearían ser puristas de transparencia referenciales para desterrar a tales operadores de puesta en escena. Esos operadores son extremadamente útiles. Programar sin ellos haciendo una puesta en escena manualmente sería tedioso, propenso a errores y feo. Y, realizar la puesta en escena de forma manual no le daría más razonamiento equitativo que el que tenía anteriormente. Entonces, prohibir los buenos dispositivos de programación en la búsqueda purista del razonamiento equitativo sería como cortarse la nariz para fastidiar la cara.
Uday Reddy
8

Si está interesado en la etimología (es decir, por qué este concepto tiene este nombre en particular), eche un vistazo a mi blog en el tema. La terminología proviene del filósofo / lógico Quine.

Andrew Birkett
fuente
4
  1. La semántica denotacional se basa en lenguajes de modelado mediante la construcción de dominios que constituyen valores denotables .
  2. Los programadores funcionales usan el término valor para describir la convergencia de un cálculo basado en las reglas de reescritura del lenguaje, es decir. su semántica operacional.

En 1 hay una claridad de dos idiomas en cuestión:

  • el que está siendo modelado, el lenguaje objeto
  • el lenguaje del modelado, el metalenguaje

En 2, gracias a la cercanía del objeto y los metalenguajes, pueden confundirse.

Como implementador del lenguaje, encuentro que necesito recordar constantemente esta distinción.

Entonces, Prof. Reddy, ¿puedo parafrasearlo así? :-)

En los contextos de programación funcional y semántica, el término Transparencia referencial no es referencialmente transparente.

Anuradha
fuente
1
Jaja. Gracias por la explicación. El problema también es que los programadores funcionales actúan como si tuvieran una noción general de "transparencia referencial" que es aplicable a todos los lenguajes de programación . Pero esto depende de su noción de "valor", que puede o no tener sentido para otros idiomas. Para reclamar una teoría general de "transparencia referencial", necesitan producir un "valor" de teoría general. Eso falta hasta ahora.
Uday Reddy
4

La siguiente respuesta, espero, agrega y califica las controvertidas 1ª y 3ª respuestas.

Permitamos que una expresión denote o se refiera a algún referente. Sin embargo, una pregunta es si estos referentes pueden codificarse isomórficamente como parte de las expresiones mismas, llamando a tales expresiones 'valores'. Por ejemplo, los valores de números literales son un subconjunto del conjunto de expresiones aritméticas, los valores de verdad son un subconjunto del conjunto de expresiones booleanas, etc. La idea es evaluar una expresión a su valor (si tiene una). Por lo tanto, la palabra 'valor' puede referirse a una denotación o a un elemento distinguido del conjunto de expresiones. Pero si hay un isomorfismo (una biyección) entre el referente y el valor, podemos decir que son lo mismo. (Dicho esto, hay que tener cuidado al definir los referentes y el isomorfismo, como lo demuestra el campo de la semántica denotacional. Para poner un ejemplo mencionado por las respuestas a la tercera respuesta,data Nat = Zero | Suc Nat no corresponde como se esperaba al conjunto de números naturales).

Escribamos E[·]para una expresión con un agujero, también conocido en algunos sectores como "contexto". Dos ejemplos de contexto para expresiones tipo C son [·]+1y [·]++.

Escribamos [[·]]para la función que toma una expresión (sin agujero) y entrega su significado (referente, denotación, etc.) en algún universo que proporciona significado. (Estoy tomando prestada la notación del campo de la semántica denotacional).

Adaptemos formalmente la definición de Quine de la siguiente manera: un contexto E[·] es referencialmente transparente si se dan dos expresiones E1y E2(sin agujeros) de modo que [[E1]] = [[E2]](es decir, las expresiones denotan / se refieren al mismo referente), entonces es el caso que [[E[E1]]] = [[E[E2]]](es decir, relleno -en el agujero con cualquiera E1o E2da como resultado expresiones que también denotan el mismo referente).

La regla de Leibniz de sustituir iguales por iguales se expresa típicamente como 'si E1 = E2entonces E[E1] = E[E2]', que dice que E[·]es una función. Una función (o, para el caso, un programa que computa la función) es un mapeo de una fuente a un objetivo, de modo que haya como máximo un elemento objetivo para cada elemento fuente. Las funciones no deterministas son nombres incorrectos, ya sea relaciones, funciones que entregan conjuntos, etc. Si en la regla de Leibniz la igualdad =es denotacional, los dobles corchetes simplemente se dan por sentados y se eluyen. Entonces, un contexto referencialmente transparente es una función. Y la regla de Leibniz es el ingrediente principal del razonamiento equitativo, por lo que el razonamiento equitativo está definitivamente relacionado con la transparencia referencial.

Aunque [[·]]es una función desde expresiones hasta denotaciones, podría ser una función desde expresiones hasta 'valores' entendidos como un subconjunto restringido de expresiones, y [[·]]puede entenderse como evaluación.

Ahora, si E1es una expresión y E2es un valor, tenemos lo que creo que entiende la mayoría de las personas al definir la transparencia referencial en términos de expresiones, valores y evaluación. Pero como se ilustra en la primera y tercera respuestas en esta página, esta es una definición incorrecta.

El problema con contextos como el [·]++no es el efecto secundario, sino que su valor no está definido en C isomorficamente a su significado. Las funciones no son valores (bueno, los punteros a las funciones sí lo son), mientras que en los lenguajes de programación funcional sí lo son. Landin, Strachey y los pioneros de la semántica denotacional fueron bastante inteligentes al usar mundos funcionales para dar significado.

Para lenguajes tipo C imperativos, podemos (aproximadamente) proporcionar semántica a las expresiones que usan la función [[·]] : Expression -> (State -> State x Value).

Valuees un subconjunto de Expression. Statecontiene pares (identificador, valor). La función semántica toma una expresión y entrega como significado una función del estado actual al par con el estado actualizado y un valor. Por ejemplo, [[x]]es la función del estado actual al par cuyo primer componente es el estado actual y cuyo segundo componente es el valor de x. En contraste, [[x++]]es la función desde el estado actual hasta el par cuyo primer componente es un estado en el que se incrementa el valor de x, y cuyo segundo componente es ese mismo valor. En este sentido, el contexto [·]++es referencialmente transparente si satisface la definición dada anteriormente.

Creo que los programadores funcionales tienen derecho a utilizar la transparencia referencial en el sentido de que se recuperan naturalmente [[·]]como una función de expresiones a valores. Las funciones son valores de primera clase y el estado también puede ser un valor, no una denotación. La mónada estatal es (en parte) un mecanismo limpio para pasar (o enhebrar) el estado.


fuente
Presumiblemente las respuestas "1ra" y "3ra" son las respuestas de UdayReddy "25 de marzo" y "postdata", respectivamente. Los ordinales no son una buena manera de referirse a las respuestas en SO. Los votos y las aceptaciones no solo pueden cambiar con el tiempo, sino que hay varios pedidos seleccionables.
philipxy
2

Tenga en cuenta que este concepto de "significado" es algo que sucede en la mente del observador. Por lo tanto, la misma "referencia" puede significar cosas diferentes para diferentes personas. Entonces, por ejemplo, tenemos una página de desambiguación de Edimburgo en Wikipedia.

Un problema relacionado que puede aparecer en el contexto de la programación podría ser el polimorfismo.

Y quizás deberíamos tener un nombre para el caso especial de polimorfismo (o tal vez incluso fundición) donde, para nuestros propósitos, los diferentes casos polimórficos son semánticamente equivalentes (en lugar de simplemente ser similares. Por ejemplo, el número 1, que podría representarse usando un tipo entero, o un tipo complejo o cualquiera de una variedad de otros tipos, puede tratarse polimórficamente).

rdm
fuente
0

La definición de transparencia referencial en el libro " Estructura e implementación de programas informáticos " (el Libro del asistente) me pareció útil porque se complementa con una explicación de cómo se viola la transparencia referencial al introducir la operación de asignación . Eche un vistazo a la siguiente diapositiva que hice sobre el tema: https://www.slideshare.net/pjschwarz/introducing-assignment-invalidates-the-substitution-model-of-evaluation-and-violates-referential-transparency-as- explicado en sicp-the-wizard-book

Philip Schwarz
fuente
0

La transparencia referencial se puede expresar simplemente como:

  • Una expresión que siempre evalúa el mismo resultado en cualquier contexto [1] ,
  • Una función, si se le dan los mismos parámetros dos veces, debe producir el mismo resultado dos veces [2] .

Por ejemplo, el lenguaje de programación Haskell es un lenguaje funcional puro; lo que significa que es referencialmente transparente.

Poder
fuente