Sistemas de tipos |
---|
Conceptos generales |
Categorías principales |
Categorías menores |
En informática y lógica , un tipo dependiente es un tipo cuya definición depende de un valor. Es una característica superpuesta de la teoría de tipos y los sistemas de tipos . En la teoría de tipos intuicionista , los tipos dependientes se utilizan para codificar cuantificadores lógicos como "para todos" y "existe". En lenguajes de programación funcional como Agda , ATS , Coq , F* , Epigram , Idris y Lean , los tipos dependientes ayudan a reducir errores al permitir que el programador asigne tipos que restringen aún más el conjunto de posibles implementaciones.
Dos ejemplos comunes de tipos dependientes son las funciones dependientes y los pares dependientes . El tipo de retorno de una función dependiente puede depender del valor (no solo del tipo) de uno de sus argumentos. Por ejemplo, una función que toma un entero positivo puede devolver una matriz de longitud , donde la longitud de la matriz es parte del tipo de la matriz. (Tenga en cuenta que esto es diferente del polimorfismo y la programación genérica , que incluyen el tipo como argumento). Un par dependiente puede tener un segundo valor, cuyo tipo depende del primer valor. Siguiendo con el ejemplo de la matriz, un par dependiente se puede utilizar para emparejar una matriz con su longitud de una manera segura para los tipos.
Los tipos dependientes añaden complejidad a un sistema de tipos. Decidir la igualdad de tipos dependientes en un programa puede requerir cálculos. Si se permiten valores arbitrarios en los tipos dependientes, entonces decidir la igualdad de tipos puede implicar decidir si dos programas arbitrarios producen el mismo resultado; por lo tanto, la decidibilidad de la verificación de tipos puede depender de la semántica de igualdad de la teoría de tipos dada, es decir, si la teoría de tipos es intensional o extensional . [1]
En 1934, Haskell Curry se dio cuenta de que los tipos utilizados en el cálculo lambda tipado y en su contraparte de lógica combinatoria seguían el mismo patrón que los axiomas en la lógica proposicional . Yendo más allá, para cada prueba en la lógica, había una función (término) correspondiente en el lenguaje de programación. Uno de los ejemplos de Curry fue la correspondencia entre el cálculo lambda tipado simple y la lógica intuicionista . [2]
La lógica de predicados es una extensión de la lógica proposicional, que añade cuantificadores. Howard y de Bruijn ampliaron el cálculo lambda para que coincidiera con esta lógica más potente creando tipos para funciones dependientes, que corresponden a "para todos", y pares dependientes, que corresponden a "existe". [3]
Debido a esto y a otros trabajos de Howard, las proposiciones como tipos se conocen como la correspondencia Curry-Howard .
En términos generales, los tipos dependientes son similares al tipo de una familia indexada de conjuntos . De manera más formal, dado un tipo en un universo de tipos , se puede tener una familia de tipos , que asigna a cada término un tipo . Decimos que el tipo varía con .
Una función cuyo tipo de valor de retorno varía con su argumento (es decir, no hay un codominio fijo ) es una función dependiente y el tipo de esta función se llama tipo de producto dependiente , tipo pi ( tipo Π ) o tipo de función dependiente . [4] A partir de una familia de tipos podemos construir el tipo de funciones dependientes , cuyos términos son funciones que toman un término y devuelven un término en . Para este ejemplo, el tipo de función dependiente se escribe típicamente como o .
Si es una función constante, el tipo de producto dependiente correspondiente es equivalente a un tipo de función ordinaria . Es decir, es igual en términos de juicio a cuando no depende de .
El nombre "Π-tipo" proviene de la idea de que estos pueden verse como un producto cartesiano de tipos. Los Π-tipos también pueden entenderse como modelos de cuantificadores universales .
Por ejemplo, si escribimos para n -tuplas de números reales , entonces sería el tipo de una función que, dado un número natural n , devuelve una tupla de números reales de tamaño n . El espacio de funciones habitual surge como un caso especial cuando el tipo de rango en realidad no depende de la entrada. Por ejemplo, es el tipo de funciones desde números naturales hasta números reales, que se escribe como en el cálculo lambda tipado.
Para un ejemplo más concreto, tomando como el tipo de números enteros sin signo de 0 a 255 (los que caben en 8 bits o 1 byte) y para , entonces se convierte en el producto de .
El dual del tipo de producto dependiente es el tipo de par dependiente , tipo de suma dependiente , tipo sigma o (confusamente) tipo de producto dependiente . [4] Los tipos sigma también pueden entenderse como cuantificadores existenciales . Continuando con el ejemplo anterior, si, en el universo de tipos , hay un tipo y una familia de tipos , entonces hay un tipo de par dependiente . (Las notaciones alternativas son similares a las de los tipos Π ).
El tipo de par dependiente captura la idea de un par ordenado donde el tipo del segundo término depende del valor del primero. Si entonces y . Si es una función constante, entonces el tipo de par dependiente se convierte en (es juzgadamente igual a) el tipo de producto , es decir, un producto cartesiano ordinario . [4]
Para un ejemplo más concreto, tomando nuevamente como tipo de enteros sin signo de 0 a 255, y nuevamente como igual a para 256 más arbitrario , entonces se convierte en la suma .
Sea algún tipo, y sea . Por la correspondencia Curry-Howard, puede interpretarse como un predicado lógico en términos de . Para un dado , si el tipo está habitado indica si satisface este predicado. La correspondencia puede extenderse a la cuantificación existencial y a los pares dependientes: la proposición es verdadera si y solo si el tipo está habitado.
Por ejemplo, es menor o igual a si y solo si existe otro número natural tal que . En lógica, esta afirmación está codificada por la cuantificación existencial:
Esta proposición corresponde al tipo de par dependiente:
Es decir, una prueba de la afirmación de que es menor o igual a es un par que contiene tanto un número no negativo , que es la diferencia entre y , como una prueba de la igualdad .
Henk Barendregt desarrolló el cubo lambda como un medio para clasificar los sistemas de tipos a lo largo de tres ejes. Las ocho esquinas del diagrama en forma de cubo resultante corresponden cada una a un sistema de tipos, con el cálculo lambda de tipos simples en la esquina menos expresiva y el cálculo de construcciones en la más expresiva. Los tres ejes del cubo corresponden a tres ampliaciones diferentes del cálculo lambda de tipos simples: la adición de tipos dependientes, la adición de polimorfismo y la adición de constructores de tipos de clase superior (funciones de tipos a tipos, por ejemplo). El cubo lambda se generaliza aún más mediante sistemas de tipos puros .
El sistema de tipos dependientes puros de primer orden, correspondiente al marco lógico LF , se obtiene generalizando el tipo de espacio de funciones del cálculo lambda simplemente tipado al tipo de producto dependiente.
El sistema de tipos dependientes de segundo orden se obtiene al permitir la cuantificación sobre los constructores de tipos. En esta teoría, el operador de producto dependiente subsume tanto el operador del cálculo lambda de tipo simple como el operador de enlace del Sistema F.
El sistema de orden superior se extiende a las cuatro formas de abstracción del cubo lambda : funciones de términos a términos, tipos a tipos, términos a tipos y tipos a términos. El sistema corresponde al cálculo de construcciones cuya derivada, el cálculo de construcciones inductivas , es el sistema subyacente del asistente de demostración Coq .
La correspondencia Curry-Howard implica que se pueden construir tipos que expresen propiedades matemáticas arbitrariamente complejas. Si el usuario puede proporcionar una prueba constructiva de que un tipo está habitado (es decir, que existe un valor de ese tipo), entonces un compilador puede comprobar la prueba y convertirla en código informático ejecutable que calcula el valor llevando a cabo la construcción. La característica de comprobación de pruebas hace que los lenguajes con tipado dependiente estén estrechamente relacionados con los asistentes de pruebas . El aspecto de generación de código proporciona un enfoque poderoso para la verificación formal de programas y el código portador de pruebas , ya que el código se deriva directamente de una prueba matemática verificada mecánicamente.
Idioma | Desarrollado activamente | Paradigma [a] | Táctica | Términos de prueba | Comprobación de terminación | Los tipos pueden depender de [b] | Universos | Irrelevancia de la prueba | Extracción de programas | La extracción borra los términos irrelevantes |
---|---|---|---|---|---|---|---|---|---|---|
Año 2012 | Sí [5] | Imperativo | Sí [6] | No | ? | Cualquier término [c] | ? | ? | Ada | ? |
Agadé | Sí [7] | Puramente funcional | Pocos/limitados [d] | Sí | Sí (opcional) | Cualquier término | Sí (opcional) [e] | Argumentos irrelevantes para la prueba [9] Proposiciones irrelevantes para la prueba [10] | Haskell , JavaScript | Sí [9] |
ATS | Sí [11] | Funcional / imperativo | No [12] | Sí | Sí | Términos estáticos [13] | ? | Sí | Sí | Sí |
Pimentón | No | Puramente funcional | No | Sí | No | Cualquier término | No | No | ? | ? |
Gallina ( Coq ) | Sí [14] | Puramente funcional | Sí | Sí | Sí | Cualquier término | Sí [f] | Sí [15] | Haskell , Esquema , OCaml | Sí |
ML dependiente | No [g] | ? | ? | Sí | ? | Números naturales | ? | ? | ? | ? |
F* | Sí [16] | Funcional e imperativo | Sí [17] | Sí | Sí (opcional) | Cualquier término puro | Sí | Sí | OCaml , F# y C | Sí |
Gurú | No [18] | Puramente funcional [19] | hipjoin [20] | Sí [19] | Sí | Cualquier término | No | Sí | Alcaravea | Sí |
Idris | Sí [21] | Puramente funcional [22] | Sí [23] | Sí | Sí (opcional) | Cualquier término | Sí | No | Sí | Sí [23] |
Inclinarse | Sí | Puramente funcional | Sí | Sí | Sí | Cualquier término | Sí | Sí | Sí | Sí |
Matita | Sí [24] | Puramente funcional | Sí | Sí | Sí | Cualquier término | Sí | Sí | OCaml | Sí |
NuPRL | Sí | Puramente funcional | Sí | Sí | Sí | Cualquier término | Sí | ? | Sí | ? |
PVS | Sí | ? | Sí | ? | ? | ? | ? | ? | ? | ? |
Sage Archivado el 9 de noviembre de 2020 en Wayback Machine. | No [h] | Puramente funcional | No | No | No | ? | No | ? | ? | ? |
CHISPA 2014 | Sí [25] | Imperativo | Sí [26] | Sí [27] | Sí [28] | Cualquier término [i] | ? | ? | Ada y C [29] | Sí [30] |
Doce | Sí | Programación lógica | ? | Sí | Sí (opcional) | Cualquier término (LF) | No | No | ? | ? |