¿Cuál es la buena explicación del Principio de correspondencia de Tennent?

21

Me encontré luchando por ver de qué se trata este principio y por qué es tan importante para el diseño del lenguaje.

Básicamente, establece que para cada expresión expren el lenguaje debe ser exactamente la misma que esta construcción:

(function () { return expr; })()

Además, he oído que Ruby obedece este principio, mientras que Python no. No entiendo por qué esto es cierto, o si es cierto en absoluto.

Andrés
fuente
3
No puedo ver por qué está fuera de tema, ¿podría alguien explicármelo?
Andrew
3
Hay un par de problemas; Lo he retocado y lo envío a los Programadores, donde discusiones como esta son un poco más bienvenidas.
Estafado
1
Ruby no obedece este principio: suponga que exprobtiene el seguimiento de la pila actual.
Landei

Respuestas:

18

Nunca antes había oído hablar del "Principio de correspondencia de Tennent" y mucho menos de que fuera importante en el diseño del lenguaje. Buscar en Google las expresiones parece llevar a un blog de Neal Gafter de 2006 que establece lo que él cree que es y cómo cree que debería aplicarse también a los cierres. Y la mayoría de los demás en los foros parecen referirse a la entrada de Gafter.

Sin embargo, aquí hay una mención de dicho "TCP" por Douglas Crockford (un nombre que conozco y en el que confío): http://java.sys-con.com/node/793338/ . En parte

Hay algunas cosas que no se pueden encerrar de esa manera, como las declaraciones de devolución y las declaraciones de ruptura, que los defensores de la afirmación del Principio de Correspondencia (TCP) de Tennent son un síntoma de mal olor. Yow! El diseño del lenguaje ya es bastante difícil sin tener que hacer frente a las alucinaciones olfativas. Entonces, para comprender mejor el problema, compré una copia del libro de Tennent de 1981, Principios de lenguajes de programación.

Resulta que el Principio de correspondencia es descriptivo , no prescriptivo . Lo utiliza para analizar el lenguaje de programación Pascal (ya olvidado), que muestra una correspondencia entre las definiciones de las variables y los parámetros del procedimiento. Tennent no identifica la falta de correspondencia de las declaraciones de devolución como un problema .

Por lo tanto, parece que el nombre "Principio de correspondencia de Tennent" está mal utilizado, y lo que sea que Neal habla posiblemente debería llamarse "TCP imaginado y posiblemente generalizado de Gafter" ... o algo así. En cualquier caso, no es suficiente para esconderse detrás de una cortina de nombre de libro agotado

Nas Banov
fuente
1
+1 para "TCP imaginado y posiblemente generalizado de
Gafter
9

Veo esto como parte de una regla general de que un lenguaje bien diseñado hace lo que un programador esperaría naturalmente. Si tengo un bloque de código que quiero refactorizar en un cierre, y envuelvo ese bloque con la sintaxis adecuada sin pensar realmente en las líneas de código individuales, entonces espero que ese bloque haga lo mismo en el cierre. hizo en línea. Si algunas declaraciones usan la palabra clave "this" (quizás implícitamente) y el lenguaje hace que "this" usado dentro del cierre se refiera a una clase anónima usada para representarlo en lugar de la clase que define el método que define el cierre, entonces el significado de esas declaraciones han cambiado, mi bloque de código ya no hace lo que creo que hace, y tengo que rastrear un error y descubrir cómo cambiar mi código para que funcione en el cierre.

El problema también podría mitigarse con un IDE con herramientas de refactorización inteligentes, que podrían extraer cierres, detectar posibles problemas e incluso ajustar automáticamente el código extraído para resolver los problemas.

JGWeissman
fuente
3

Claus Reinke: con respecto al "Diseño del lenguaje basado en principios semánticos" de Tennent,
ofrece una interpretación interesante de los principios:
"La correspondencia es el principio que nos permite decir que

let(this=obj, x=5) { .. }  

y

((function(x) { .. }).call(obj,5))  

debería ser equivalente, y que cualquier cosa que podamos hacer en las listas formales de parámetros, también deberíamos poder hacerlo en las declaraciones, y viceversa. "[ver también, Reinke, a continuación.]

Tendencia RD: Métodos de diseño del lenguaje basados ​​en principios semánticos
"Dos métodos de diseño del lenguaje basados ​​en principios derivados del enfoque denotacional para la semántica del lenguaje de programación se describen e ilustran mediante una aplicación al lenguaje Pascal. Los principios son, en primer lugar, la correspondencia entre lo paramétrico y mecanismos declarativos y, en segundo lugar, un principio de abstracción para lenguajes de programación adaptados de la teoría de conjuntos. Varias extensiones y generalizaciones útiles de Pascal surgen mediante la aplicación de estos principios, incluida una solución al problema de los parámetros de la matriz y una instalación de modularización ".

Claus Reinke: "Sobre programación funcional, diseño de lenguaje y persistencia" en Haskell

Kris
fuente
Claus Reinke: "Sobre programación funcional, diseño de lenguaje y persistencia" en Haskell en community.haskell.org/~claus/publications/fpldp.html
Kris
2

Para responder a la pregunta de por qué el CP de Tennent es tan importante para el diseño del lenguaje, me gustaría citar a Neal Gafter :

Los principios de Tennent son muy poderosos porque las violaciones de ellos tienden a aparecer en el idioma como fallas, irregularidades, restricciones innecesarias, interacciones o complicaciones inesperadas, etc.

Es probable que cualquier violación de TCP perjudique a algún programador en el futuro cuando espera que los cierres funcionen como un código de no cierre, pero descubre que, en violación de TCP, no lo hacen.

thiton
fuente
1

RE Python no sigue este principio. En general, sigue el principio. Ejemplo básico:

>>> x = ['foo']
>>> x
['foo']
>>> x = (lambda: ['foo'])()
>>> x
['foo']

Sin embargo, Python define expresiones y declaraciones por separado. Dado que las iframas, los whilebucles, la asignación destructiva y otras declaraciones no se pueden usar en lambdaexpresiones, la letra del principio de Tennent no se aplica a ellos. Aun así, restringirse a usar solo expresiones de Python todavía produce un sistema completo de Turing. Así que no veo esto como una violación del principio; o más bien, si viola el principio, entonces ningún lenguaje que defina declaraciones y expresiones por separado puede ajustarse al principio.

Además, si el cuerpo de la lambdaexpresión capturara un rastro de la pila o realizara otra introspección en la máquina virtual, eso podría causar diferencias. Pero en mi opinión, esto no debe considerarse como una violación. Si expry (lambda: expr)() necesariamente compila al mismo bytecode, entonces el principio realmente concierne a los compiladores, no a la semántica; pero si pueden compilar a diferentes bytes, no deberíamos esperar que el estado de la VM sea idéntico en cada caso.

Se puede encontrar una sorpresa usando la sintaxis de comprensión, aunque creo que esto tampoco es una violación del principio de Tennent. Ejemplo:

>>> [x for x in xrange(10)]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> [f() for f in [lambda: x for x in xrange(10)]]  # surprise!
[9, 9, 9, 9, 9, 9, 9, 9, 9, 9]
>>> # application of Tennent principle to first expression
... [(lambda: x)() for x in xrange(10)]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> [f() for f in [(lambda x: lambda: x)(x) for x in xrange(10)]]  # force-rebind x
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> map(lambda f:f(), map(lambda x: lambda: x, xrange(10)))  # no issue with this form
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

La sorpresa es el resultado de cómo se definen las comprensiones de listas. La comprensión 'sorpresa' anterior es equivalente a este código:

>>> result = []
>>> for x in xrange(10):
...   # the same, mutable, variable x is used each time
...   result.append(lambda: x)
... 
>>> r2 = []
>>> for f in result:
...   r2.append(f())
... 
>>> r2
[9, 9, 9, 9, 9, 9, 9, 9, 9, 9]

Visto de esta manera, la comprensión 'sorpresa' anterior es menos sorprendente, y no una violación del principio de Tennent.

fresa
fuente