functional-programming computer-science theory referential-transparency

functional programming - ¿Qué es la transparencia referencial?



functional-programming computer-science (12)

  1. La semántica denotacional se basa en el modelado de idiomas mediante la construcción de dominios que constituyen valores denotables.
  2. Los programadores funcionales utilizan 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 lenguaje meta.

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

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

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

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

¿Qué significa el término transparencia referencial ? He escuchado que se describe como "significa que puedes reemplazar iguales por iguales", pero esto parece una explicación inadecuada.


El término "transparencia referencial" proviene de la filosofía analítica , la rama de la filosofía que analiza las construcciones del lenguaje natural, las declaraciones y los 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 su esencia, la "transparencia referencial" es una idea muy simple y clara. El término "referente" se usa en la filosofía analítica para hablar sobre lo que se refiere a una expresión . Es aproximadamente lo mismo que entendemos por "significado" o "denotación" en la semántica del lenguaje de programación. Utilizando 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 refiere 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.

Así que el contexto "El Parlamento escocés se reúne en ..." es un contexto de referencia transparente. Podemos reemplazar "la capital de Escocia" por "Edimburgo" sin alterar el significado. Dicho de otra manera, 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 frase,

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, 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). Al parecer, se preocupa por algo más de lo que el término se refiere. ¿Qué es?

Cosas como "la capital de Escocia" se denominan términos definidos y no causaron mucho dolor de cabeza a los lógicos y filósofos durante mucho tiempo. Russell y Quine los clasificaron 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 frase no puede ser transformada en una loca. ¡Problema resuelto! El objetivo de Quine era decir que el lenguaje natural es complicado, o al menos complicado, porque está diseñado para ser práctico para el uso práctico, pero los filósofos y los lógicos deben aportar claridad al entenderlos de la manera correcta. La transparencia referencial es una herramienta que se utiliza para aportar tanta claridad de significado .

¿Qué tiene todo esto que ver con la programación? No mucho, en realidad. Como dijimos, la transparencia referencial es una herramienta que se utiliza para comprender el lenguaje, es decir, para asignar significado . Christopher Strachey , quien fundó el campo de la semántica del lenguaje de programación, lo utilizó en su estudio del significado. Su artículo fundacional " Conceptos fundamentales en lenguajes de programación " está disponible en la web. Es un hermoso papel y todos pueden leerlo y entenderlo. Así que, 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 subexpresión, lo único que necesitamos saber sobre la subexpresió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 que están escritas, son irrelevantes para el valor de la letra 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 otras 9 apariciones de "transparencia referencial" en el documento, pero no parecen preocuparse por ninguna de las otras. De hecho, todo el documento de Strachey está dedicado a explicar el significado de los lenguajes de programación imperativos . Pero, hoy en día, los programadores funcionales afirman que los lenguajes de programación imperativos no son referencialmente transparentes. Strachey estaría girando 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 deban confundirnos. Solo tienen que ser entendidos de la manera correcta, utilizando un lenguaje meta que sea referencialmente transparente para que tengamos claridad de significado. En el documento que cité, Strachey hace exactamente eso. Explica el significado de los lenguajes de programación imperativos desglosándolos en conceptos elementales, sin perder nunca claridad en ninguna parte. Una parte importante de su análisis es señalar que las expresiones en los lenguajes de programación tienen dos tipos de "valores", llamados valores de l y valores de r . Antes del artículo de Strachey, esto no se entendía y la confusión reinaba. Hoy en día, la definición de C lo menciona rutinariamente y cada programador de C entiende la distinción. (Es difícil decir si los programadores en otros idiomas lo entienden 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 que "la capital de Escocia" depende del momento en que se está considerando. Dicha dependencia del contexto es una realidad, tanto en los lenguajes naturales como en los lenguajes de programación. Incluso en la programación funcional, las variables libres y limitadas deben interpretarse con respecto al contexto en el que aparecen. La dependencia del contexto de cualquier tipo bloquea la transparencia referencial de una u otra forma. Si intenta comprender el significado de los términos sin tener en cuenta los contextos de los que dependen, volverá a confundirse. A Quine le preocupaba el significado de la lógica modal. Sostuvo que la lógica modal era referencialmente opaca y que debería ser limpiada traduciéndola a un marco referencialmente transparente (por ejemplo, considerando la necesidad como demostrable). En gran parte perdió este debate. Tanto los lógicos como los filósofos consideraron que la posible semántica mundial de Kripke era perfectamente adecuada. 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 una 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 "acercar" 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 muy 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 bien, podríamos hablar de su valor l que abarca todos los estados. Las personas rara vez son confundidas por 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 estas capas de significado no son necesariamente "obvias" y es un asunto de la ciencia estudiarlas correctamente. Sin embargo, la inarticulación de la gente común para explicar tales significados en capas no implica que estén confundidos acerca de ellos.]

Una "posdata" separada a continuación relaciona esta discusión con las preocupaciones de la programación funcional e imperativa .


En la programación funcional, la transparencia referencial generalmente se define como el hecho de que una expresión, en un programa, puede ser reemplazada por su valor (o cualquier cosa que tenga el mismo valor) sin cambiar el resultado del programa. Esto implica que los métodos siempre deben devolver el mismo valor para un argumento dado, sin tener ningún otro efecto. Sin embargo, este concepto de programación funcional también se aplica a la programación imperativa y puede ayudarlo a aclarar su código.

Transparencia referencial

La expresión transparencia referencial se utiliza en varios dominios, como matemática, lógica, lingüística, filosofía y programación. Tiene significados muy diferentes en cada uno de estos dominios. Aquí, solo trataremos con programas de computadora, aunque mostraremos una analogía con las matemáticas (matemáticas simples, no te preocupes). Tenga en cuenta, sin embargo, que los informáticos no están de acuerdo con el significado de la transparencia referencial en la programación. Lo que veremos es la transparencia referencial, ya que es utilizada por programadores funcionales.

Transparencia de referencia en matemáticas En matemáticas, la transparencia de referencia es la propiedad de las expresiones que pueden reemplazarse por otras expresiones que tienen el mismo valor sin cambiar el resultado de ninguna manera. Considere el siguiente ejemplo:

x = 2 + (3 * 4)

Podemos reemplazar la subexpresión (3 * 4) con cualquier otra expresión que tenga el mismo valor sin cambiar el resultado (el valor de x). La expresión más evidente a utilizar, es por supuesto 12:

x = 2 + 12

Cualquier otra expresión que tenga el valor 12 (quizás (5 + 7)) podría usarse sin cambiar el resultado. Como consecuencia, la subexpresión (3 * 4) es referencialmente transparente.

También podemos reemplazar la expresión 2 + 12 por otra expresión que tenga el mismo valor sin cambiar el valor de x, por lo que también es referencialmente transparente:

x = 14

Puede ver fácilmente el beneficio de la transparencia referencial: permite el razonamiento. Sin él, no podríamos resolver ninguna expresión sin considerar algunos otros elementos.

Transparencia referencial en la programación En la programación, la transparencia referencial se aplica a los programas. Como los programas están compuestos por subprogramas, que son programas en sí mismos, también se aplican a esos subprogramas. Los subprogramas pueden ser representados, entre otras cosas, por métodos. Eso significa que el método puede ser referencialmente transparente, que es el caso si una llamada a este método puede ser reemplazada por su valor de retorno:

int add(int a, int b) { return a + b } int mult(int a, int b) { return a * b; } int x = add(2, mult(3, 4));

En este ejemplo, el método mult es referencialmente transparente porque cualquier llamada a este puede reemplazarse con el valor de retorno correspondiente. Esto se puede observar reemplazando mult (3, 4) con 12:

int x = add(2, 12)

De la misma manera, add (2, 12) se puede reemplazar con el valor de retorno correspondiente, 14:

int x = 14;

Ninguno de estos reemplazos cambiará el resultado del programa, haga lo que haga. Tenga en cuenta que podríamos usar cualquier otra expresión que tenga el mismo valor, lo cual es útil al refactorizar.

Por otro lado, considere el siguiente programa:

int add(int a, int b) { int result = a + b; System.out.println("Returning " + result); return result; }

Reemplazar una llamada al método de adición con el valor de retorno correspondiente cambiará el resultado del programa, ya que el mensaje ya no se imprimirá. En ese caso, solo eliminaría el efecto secundario, pero en otros casos, podría cambiar el valor devuelto por el método:

public static void main(String... args) { printFibs(10); } public static void printFibs(int limit) { Fibs fibs = new Fibs(); for (int i = 0; i < limit; i++) { System.out.println(fibs.next()); } } static class Fibs { private int previous = -1; private int last = 1; public Integer next() { last = previous + (previous = last); return previous + last; } }

Aquí, el siguiente método no se puede reemplazar con nada que tenga el mismo valor, ya que el método está diseñado para devolver un valor diferente en cada llamada.

El uso de estos métodos no referencialmente transparentes requiere una fuerte disciplina para no compartir el estado mutable involucrado en el cálculo. El estilo funcional evita tales métodos a favor de versiones referencialmente transparentes.

Transparencia referencial en la programación imperativa Tanto la programación imperativa como la funcional utilizan funciones. Aunque la programación funcional usa solo funciones, la programación imperativa usa:

  • Funciones puras: métodos que devuelven valores y no tienen otros efectos.
  • Efectos puros: métodos que no devuelven nada más que cambiar algo fuera de ellos.
  • Funciones con efectos secundarios: métodos que devuelven un valor y cambian algo.

Como todos sabemos, es una buena práctica evitar las funciones con efectos secundarios. Esto deja a los programadores imperativos con funciones puras y efectos puros. La transparencia referencial es entonces una herramienta poderosa para que los programadores imperativos hagan que sus programas sean más fáciles de razonar y más fáciles de probar.


Espero que la siguiente respuesta añada y califique las controvertidas respuestas primera y tercera.

Admitamos que una expresión denota o se refiere a algún referente. Sin embargo, una pregunta es si estos referentes pueden codificarse isomorfamente como parte de las expresiones en sí, 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 uno). Entonces, la palabra ''valor'' puede referirse a una denotación o a un elemento distinguido del conjunto de expresiones. Pero si hay un isomorfismo (una bijección) entre el referente y el valor, podemos decir que son la misma cosa. (Dicho esto, se debe tener cuidado al definir los referentes y el isomorfismo, como lo demuestra el campo de la semántica denotacional. Para poner un ejemplo mencionado en las respuestas a la tercera respuesta, los datos de definición de tipos de datos algebraicos data Nat = Zero | Suc Nat hace no corresponde como se espera al conjunto de números naturales.)

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

Escribamos [[·]] para la función que toma una expresión (sin agujero) y ofrece 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).

Permítanos adaptar la definición de Quine de manera formal como sigue: un contexto E[·] es referencialmente transparente si se le dan dos expresiones E1 y E2 (sin orificios) de modo que [[E1]] = [[E2]] (es decir, las expresiones denotan / refiera al mismo referente) entonces es el caso que [[E[E1]]] = [[E[E2]]] (es decir, rellenar el orificio con E1 o E2 da 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 = E2 entonces E[E1] = E[E2] '', que dice que E[·] es una función. Una función (o, para el caso, un programa que calcula la función) es una asignación de un origen a un destino, de modo que haya como máximo un elemento de destino para cada elemento de origen. Las funciones no deterministas son nombres inapropiados, son relaciones, funciones que entregan conjuntos, etc. Si en la regla de Leibniz la igualdad = es denotacional, entonces los paréntesis dobles simplemente se dan por sentado y se eliminan. Entonces, un contexto referencialmente transparente es una función. Y la regla de Leibniz es el ingrediente principal del razonamiento ecuacional, por lo que el razonamiento ecuacional está definitivamente relacionado con la transparencia referencial.

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

Ahora, si E1 es una expresión y E2 es un valor, tenemos lo que creo que significa la mayoría de las personas al definir la transparencia referencial en términos de expresiones, valores y evaluación. Pero como lo ilustran las respuestas 1 y 3 en esta página, esta es una definición incorrecta.

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

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

Value es un subconjunto de Expression . State contiene pares (identificador, valor). La función semántica toma una expresión y entrega como su 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 del estado actual al par cuyo primer componente es un estado en el que el valor de x se incrementa, y cuyo segundo componente es ese mismo valor. En este sentido, el contexto [·]++ es referencialmente transparente si cumple con la definición dada anteriormente.

Creo que los programadores funcionales tienen derecho a usar la transparencia referencial en el sentido de que naturalmente recuperan [[·]] 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 de estado es (en parte) un mecanismo limpio para pasar (o enhebrar) el estado.


La transparencia referencial, un término comúnmente usado 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, podría 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, simplemente 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 tiene una función transparente referencial, se presta para una fácil paralelización automática 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 no siempre produce 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 normalmente operan en sus variables miembro y, por lo tanto, serían opacas referenciales. Sin embargo, las funciones de los miembros pueden ser, por supuesto, referencialmente transparentes.

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


Para aquellos que necesiten una explicación concisa, me arriesgaré a una (pero lea la descripción a continuación).

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

fx = x + x,

La facilidad con la que puede (de manera segura) reemplazar f (foo) con foo + foo en el ámbito 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 es su lenguaje de programación. tiene.

Por ejemplo, si foo fuera x ++ en el sentido de programación en C, entonces no podría realizar esta reducción de forma segura (es decir, si tuviera que realizar 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 perfecta transparencia referencial, pero los programadores funcionales se preocupan más por ella que la mayoría (vea Haskell, donde es un objetivo central).

(Revelación completa: soy un programador funcional, por lo tanto, con la respuesta superior, debe tomar esta explicación con un grano de sal).


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


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 diferentes cosas para diferentes personas. Así, 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 tal vez deberíamos tener un nombre para el caso especial de polimorfismo (o tal vez incluso fundido) donde, para nuestros propósitos, los diferentes casos polimórficos son semánticamente equivalentes (en oposición a ser simplemente similares. Por ejemplo, el número 1, que podría estar representado utilizando un tipo entero, o un tipo complejo o cualquiera de una variedad de otros tipos - puede tratarse polimorfamente).


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


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 un estado propio.


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


[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 la transparencia referencial de los programadores funcionales 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 su trabajo. Noté 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 Landin y Strachey introdujeron, pero parece hacer una gran diferencia cuando se usa de forma ingenua.)

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

  • Parece que creen que estos "valores" se deben obtener mediante 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 se puede reemplazar con 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 refiere a la misma cosa (una expresión de referencia ). ¿Quiénes son estos filósofos / lógicos? Incluyen Frege , Russell , Whitehead , Carnap , Quine , Church y muchos otros. Cada uno de ellos es una figura imponente. El poder intelectual combinado de estos lógicos es conmovedor para 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 de anidamiento, (b) cada subexpresión denota algo (generalmente un número, valor de verdad o función numérica) , (c) lo que una expresión denota, es decir, su "valor", depende solo de la valores de sus sub-expresiones, no en otras propiedades de ellos. [Énfasis añadido]

Stoy :

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

Pájaro y Wadler :

el valor de una expresión depende solo de los valores de sus expresiones constituyentes (si corresponde) y estas subexpresiones pueden ser reemplazadas libremente por otras que tengan el mismo valor [énfasis añadido].

Entonces, en retrospectiva, los esfuerzos de Landin y Strachey para simplificar la terminología al reemplazar "referencia" / "denotación" por "valor" podrían haber sido imprudentes. Tan pronto como uno oye hablar de un "valor", existe la tentación de pensar en un proceso de evaluación que lo lleve a él. Es igualmente tentador pensar en lo que la evaluación produce como el "valor", aunque podría ser bastante claro que esa no es la denotación. Eso es lo que supongo 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 así. 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 mencionó 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ó los comandos en 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 transformador de estado que mapea 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 tales lenguajes "referencialmente transparentes" simplemente implica que son reacios a admitir tales objetos matemáticos / conceptuales complejos como "valores". Por otro lado, parecen perfectamente dispuestos a llamar "valor" a un transformador de estado cuando se coloca en su propia sintaxis favorita y se viste con una palabra de moda como "mónada". Debo decir que están siendo totalmente inconsistentes, incluso si les concedemos que su idea de "transparencia referencial" tenga alguna 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-65, 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 llegó a ser conocido como CPL. Este era un lenguaje de programación imperativo, pero estaba destinado a tener también potentes capacidades de lenguaje de programación funcional. Landin, que era empleado de Strachey en su compañía 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 " Landin ", Landin promueve descaradamente los lenguajes de programación funcionales (llamándolos lenguajes denotativos ) y describe los lenguajes de programación imperativos como su "antítesis". En la discusión subsiguiente, encontramos a Strachey levantando dudas sobre la fuerte posición de Landin.

... Los DL forman un subconjunto de todos los idiomas. Son un subconjunto interesante, pero uno que es inconveniente de usar a menos que esté acostumbrado. Los necesitamos porque en este momento no sabemos cómo construir pruebas con lenguajes que incluyen 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 imperativos y saltos. Para 1967, estaba preparado con una teoría, que impartió 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 se habían publicado pero "desafortunadamente, debido a la edición dilatoria, los procedimientos nunca se materializaron; como gran parte del trabajo de Strachey en Oxford, sin embargo, el periódico tenía 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 confían en fuentes secundarias y rumores. Pero, ahora que los " Conceptos fundamentales " están disponibles en la web, no es necesario recurrir a la conjetura de trabajo. Debemos leerlo y decidirnos a qué se refería Strachey. En particular:

  • En la sección 3.2, trata sobre "expresiones" donde habla de "transparencia referencial de valor R".
  • Su sección 3.3 trata sobre los "comandos" cuando habla de "transparencia referencial de valor L".
  • En la sección 3.4.5, habla de "funciones y rutinas" y declara que "cualquier desviación de la transparencia referencial de valor R en un contexto de valor R debe 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 charla de "transparencia referencial" sin entender la distinción entre valores L, valores R y otros objetos complejos que pueblan el imperativo universo conceptual del programador es fundamentalmente errónea.