Esta podría ser una pregunta filosófica, pero creo que hay una respuesta objetiva.
Si lees el artículo de Wikipedia sobre Haskell, puedes encontrar lo siguiente:
El lenguaje se basa en las observaciones de Haskell Curry y sus descendientes intelectuales, que "una prueba es un programa; la fórmula que prueba es un tipo para el programa"
Ahora, lo que pregunto es: ¿esto realmente no se aplica a casi todos los lenguajes de programación? ¿Qué característica (o conjunto de características) de Haskell hace que cumpla con esta declaración? En otras palabras, ¿cuáles son las formas notables en que esta declaración afectó el diseño del lenguaje?
Respuestas:
El concepto esencial se aplica universalmente de alguna manera, sí, pero rara vez de manera útil.
Para comenzar, desde la perspectiva de la teoría de tipos, esto supone que los lenguajes "dinámicos" se consideran mejor como que tienen un solo tipo, que contiene (entre otras cosas) metadatos sobre la naturaleza del valor que ve el programador, incluido lo que estos lenguajes dinámicos llamarían un "tipo" en sí (que no es lo mismo, conceptualmente). Es probable que cualquier prueba de este tipo no sea interesante, por lo que este concepto es principalmente relevante para los lenguajes con sistemas de tipo estático.
Además, muchos lenguajes que supuestamente tienen un "sistema de tipos estático" deben considerarse dinámicos en la práctica, en este contexto, porque permiten la inspección y conversión de tipos en tiempo de ejecución. En particular, esto significa cualquier lenguaje con soporte incorporado por defecto para "reflexión" o similar. C #, por ejemplo.
Haskell es inusual en la cantidad de información que espera que proporcione un tipo, en particular, las funciones no pueden depender de ningún valor que no sean los especificados como sus argumentos. En un lenguaje con variables globales mutables, por otro lado, cualquier función puede (potencialmente) inspeccionar esos valores y cambiar el comportamiento en consecuencia. Por lo tanto, una función Haskell con tipo
A -> B
puede considerarse como un programa en miniatura que demuestra queA
implicaB
; una función equivalente en muchos otros idiomas solo nos dirá esoA
y lo que sea que sea el estado global en el alcance combinado implicaB
.Tenga en cuenta que si bien Haskell tiene soporte para cosas como la reflexión y los tipos dinámicos, el uso de tales características debe indicarse en la firma de tipo de una función; igualmente para el uso del estado global. Ninguno de los dos está disponible por defecto.
También hay formas de romper las cosas en Haskell, por ejemplo, permitiendo excepciones de tiempo de ejecución, o usando operaciones primitivas no estándar proporcionadas por el compilador, pero éstas tienen la gran expectativa de que solo se usarán con plena comprensión de formas que ganaron ' No dañar el significado del código externo. En teoría, se podría decir lo mismo de otros idiomas, pero en la práctica con la mayoría de los otros idiomas es más difícil lograr cosas sin "hacer trampa" y menos mal visto "hacer trampa". Y, por supuesto, en verdaderos lenguajes "dinámicos" todo el asunto sigue siendo irrelevante.
El concepto también puede llevarse mucho más lejos de lo que está en Haskell.
fuente
Tienes razón en que la correspondencia Curry-Howard es algo muy general. Vale la pena familiarizarse con un poco sobre su historia: http://en.wikipedia.org/wiki/Curry-Howard_correspondence
Notarás que, tal como se formuló originalmente, esta correspondencia se aplicaba particularmente a la lógica intuicionista por un lado, y al cálculo lambda simplemente escrito (STLC) por el otro.
Haskell clásico: versiones del '98 o incluso anteriores, se acercaban mucho al STLC, y en su mayor parte había una traducción directa muy simple entre cualquier expresión dada en Haskell y un término correspondiente en el STLC (extendido con recursión y unos pocos tipos primitivos). Entonces esto hizo que Curry-Howard fuera muy explícito. Hoy, gracias a las extensiones, dicha traducción es un negocio algo más complicado.
Entonces, en cierto sentido, la pregunta es por qué Haskell se "desugará" en el STLC de manera tan directa. Se me ocurren dos cosas:
También hay una forma importante en que Haskell, como la mayoría de los idiomas, falla con respecto a una aplicación directa de la correspondencia Curry-Howard. Haskell, como lenguaje completo de turing, contiene la posibilidad de recurrencia ilimitada y, por lo tanto, de no terminación. El STLC no tiene un operador de punto fijo, no está completo y se está normalizando fuertemente , lo que significa que ninguna reducción de un término en el STLC no terminará. La posibilidad de recurrencia significa que uno puede "engañar" a Curry-Howard. Por ejemplo,
let x = x in x
tiene el tipoforall a. a
Es decir, como nunca regresa, ¡puedo fingir que me da algo! Como siempre podemos hacer esto en Haskell, eso significa que no podemos "creer" completamente en ninguna prueba correspondiente a un programa de Haskell a menos que tengamos una prueba por separado de que el programa en sí está finalizando.El linaje de la programación funcional anterior a Haskell (especialmente la familia ML) fue el resultado de la investigación de CS centrada en la construcción de lenguajes sobre los que fácilmente podría probar cosas (entre otras cosas), investigación muy consciente y derivada de CH para comenzar. Por el contrario, Haskell ha servido como lenguaje anfitrión y como inspiración para una serie de asistentes de pruebas en desarrollo, como Agda y Epigram, que se basan en desarrollos en la teoría de tipos muy relacionados con el linaje de CH.
fuente
A -> B
, dada unaA
, producirá unaB
o nada en absoluto. Nunca producirá unC
, y qué valor de tipoB
proporciona, o si diverge, todavía depende exclusivamente delA
proporcionado.Void
, ¿no? La pereza hace que sea más y menos complicado ambos. Yo diría que una función deA -> B
siempre produce un valor de tipoB
, pero ese valor puede tener menos información de la que cabría esperar.Para una aproximación de primer orden, la mayoría de los otros idiomas (débilmente y / o tipados) no admiten la delineación estricta de nivel de idioma entre un
y la estricta relación entre los dos. En todo caso, las mejores garantías que brindan otros idiomas son
Tenga en cuenta que por tipo , nos referimos a una proposición y, por lo tanto, algo que describe mucha más información que simplemente int o bool . En Haskell, existe una cultura permeadora de una función que solo se ve afectada por sus argumentos , sin excepciones *.
Para ser un poco más riguroso, la idea general es que al aplicar un enfoque intuitivo rígido a (casi) todas las construcciones de programas (es decir, solo podemos probar lo que podemos construir), y al limitar el conjunto de construcciones primitivas en tal manera que tenemos
Las construcciones de Haskell tienden a prestarse muy bien al razonamiento sobre su comportamiento. Si podemos construir una prueba (léase: función) que demuestre que
A
implicaB
, esta tiene propiedades muy útiles:A
, podemos construir unaB
)A
, y nada más.lo que nos permite razonar sobre invariantes locales / globales de manera efectiva. Para volver a la pregunta original; Las características del lenguaje de Haskell que fascinan mejor esta mentalidad son:
Ninguno de los cuales es exclusivo de Haskell (muchas de estas ideas son increíblemente antiguas). Sin embargo, cuando se combina con un rico conjunto de abstracciones en las bibliotecas estándar (generalmente se encuentran en clases de tipos), diversos niveles de sintaxis y un estricto compromiso con la pureza en el diseño del programa, terminamos con un lenguaje que de alguna manera logra ser ambos lo suficientemente práctico para aplicaciones del mundo real , pero al mismo tiempo resulta más fácil razonar sobre los idiomas más tradicionales.
Esta pregunta merece una respuesta suficientemente profunda, y no podría hacerle justicia en este contexto. Sugeriría leer más en wikipedia / en la literatura:
* NB: estoy pasando por alto / ignorando algunos de los aspectos más difíciles de las impurezas de Haskell (excepciones, no terminación, etc.) que solo complicarían el argumento.
fuente
Que caracteristica El sistema de tipos (siendo estático, puro, polimórfico). Un buen punto de partida es "Theorems for Free" de Wadler. ¿Efecto notable en el diseño del lenguaje? El tipo IO, clases de tipo.
fuente
La jerarquía de Kleene nos muestra que las pruebas no son programas.
La primera relación recursiva es:
Las primeras relaciones recursivamente enumerables son:
De modo que un programa es un teorema y la iteración que existe en la que el programa se detiene es como la prueba que existe que prueba el teorema.
Cuando un programa se produce correctamente a partir de una especificación, debemos ser capaces de demostrar que cumple con la especificación, y si podemos demostrar que un programa cumple con una especificación, entonces es la síntesis correcta del programa. Entonces realizamos la síntesis del programa si demostramos que el programa cumple con la especificación. El teorema de que el programa satisface la especificación es el programa en el sentido de que el teorema se refiere al programa que se sintetiza.
Las falsas conclusiones de Martin Lof nunca han producido ningún programa de computadora y es sorprendente que la gente crea que es una metodología de síntesis de programas. Nunca se han dado ejemplos completos de un programa que se sintetiza. Una especificación como "ingresar un tipo y generar un programa de ese tipo" no es una función. Existen múltiples programas de este tipo y elegir uno al azar no es una función recursiva o incluso una función. Es solo un intento tonto de mostrar la síntesis del programa con un programa tonto que no representa un programa de computadora real que calcule una función recursiva.
fuente
doesn't this really apply to pretty much all the programming languages?
" Esta respuesta afirma / muestra que la suposición no es válida, por lo que no tiene sentido abordar el resto de las preguntas que se basan en una premisa errónea .