Nivel 5 · El cubo-λ
λP: tipos dependientes
El corazón de la matemática reside en la lógica de predicados, que se basa en proposiciones cuya verdad depende de valores concretos. No se puede expresar « es un número par» si el tipo que representa a la proposición no puede depender del término .
Se necesita cerrar esta brecha: se requiere que los tipos (que representan proposiciones) puedan depender de los términos. Esta es la extensión que define el Sistema . Al permitir esta dependencia, el sistema proporciona una forma de codificar directamente la cuantificación universal de la lógica: la afirmación se convierte en el tipo . Este es el paso que eleva la teoría de tipos de una simple lógica de proposiciones a una lógica robusta de predicados, sentando las bases para la formalización de la matemática. La presentación sigue a Nederpelt y Geuvers (2014) .
Tipos que dependen de términos
La idea central de es permitir que las familias de tipos sean indexadas no por otros tipos (como en ), sino por términos: un tipo puede cambiar su forma en función de un valor.
Un ejemplo computacional clásico es el de un vector de longitud fija. Se desea tener un tipo, , que dependa no solo del tipo de sus elementos (por ejemplo ), sino también de un valor numérico que especifique su longitud. Así se tendrían tipos como:
- : el tipo de los vectores de naturales de longitud (la lista vacía).
- : el tipo de los vectores de naturales de longitud (como ).
- : el tipo de los vectores de booleanos de longitud (como ).
Fijado el tipo de los elementos, el constructor tiene el kind : una familia de tipos indexada por términos. (La versión totalmente genérica requiere además la dependencia , y pertenece a o , no a .)
Esta misma idea se traduce directamente al lenguaje de la lógica. Un predicado, como «ser un número par», puede ser visto como una familia de proposiciones (tipos) indexada por los números naturales:
Al aplicar este predicado a un término se obtiene un tipo específico:
- : el tipo que representa la proposición «2 es par». Este tipo está habitado (es decir, existe una prueba para él).
- : el tipo que representa la proposición «3 es par». Este tipo está vacío (no existe una prueba para él).
La lógica de predicados como un sistema de tipos
La verdadera fuerza de se revela cuando se aplica la correspondencia de proposiciones como tipos (PAT, por sus siglas en inglés de Propositions As Types, la correspondencia de Curry–Howard del módulo anterior) a este nuevo poder de dependencia. Esto permite codificar la lógica de predicados de primer orden directamente en el sistema de tipos.
La correspondencia se extiende de la siguiente manera:
- Proposiciones: se representan como tipos de kind .
- Pruebas de proposiciones: se representan como términos que habitan el tipo correspondiente.
- Predicados sobre un conjunto (por ejemplo ): se representan como constructores de tipos de la forma .
- La implicación (): se representa con el tipo función . Probar es construir un término de tipo .
- La cuantificación universal (): se representa con el tipo producto dependiente . Probar esta afirmación es construir un término (una función dependiente) que, para cualquier término , produce un término (una prueba) de tipo .
Bajo esta interpretación, las reglas de inferencia de la lógica aparecen de forma natural a partir de las reglas de tipado del cálculo. Por ejemplo, la regla de eliminación para (especialización) es simplemente la regla de aplicación de una función dependiente, y la regla de introducción (generalización) es la regla de abstracción.
Ejemplo: construyendo una prueba formal
Para ver el sistema en acción, se construirá una prueba formal para un teorema simple de la lógica de predicados. Se considera la siguiente proposición: si es verdadero para todos los pares , entonces es verdadero para todos los pares de la forma . Formalmente:
El objetivo es construir un término que habite el tipo correspondiente en .
Objetivo: encontrar un habitante para el tipo
donde es un conjunto y es un predicado de dos argumentos. Usando la notación de banderas, y siguiendo la sección 5.5 de Nederpelt y Geuvers (2014) , se tiene:
| (a) | ||
| (b) | ||
| (c) | ||
| (d) | ||
| (1) | (aplicación) en (c) y (d) | |
| (2) | (aplicación) en (1) y (d) | |
| (3) | (abstracción) en (2) | |
| (4) | (abstracción) en (3) |
Cada paso se justifica así: en (1), la hipótesis (una prueba de que vale para todos los pares) se aplica al término , especializando el primer cuantificador; en (2) se aplica de nuevo a , especializando el segundo; en (3) la abstracción sobre descarga la bandera (d) e introduce el cuantificador ; y en (4) la abstracción sobre descarga la bandera (c) e introduce la implicación. El término final, , es el habitante que se buscaba. En general es un algoritmo: una construcción basada en los principios lógicos.
Las reglas Π de λP
El sistema se formaliza con un conjunto de reglas del mismo esquema que el de (sort, variable, debilitamiento, formación, aplicación, abstracción, conversión), sustituyendo el conector por el producto dependiente . Nótese que no contiene a : en no se forman kinds como , pues carece de la dependencia . Las tres reglas donde aparece el producto dependiente son:
La regla (abstracción) es la que justifica los pasos (3) y (4) de la derivación de banderas anterior. La regla (formación) permite crear tipos dependientes ; la restricción clave de es que la dependencia debe ser sobre una variable de un tipo simple (). Sin embargo, la construcción es general: el tipo resultante es de sort , lo que significa que no solo formaliza proposiciones que dependen de términos (el caso ), sino también kinds que dependen de términos (el caso ), como el kind de los predicados de la Definición 8.25.
Ejemplo en Lean
La sección teórica culmina con la prueba del teorema
El término-prueba que se construye, , se traduce de
manera casi literal en Lean. Aquí forall es la notación de Lean para el tipo producto
dependiente y Prop es el tipo de todas las proposiciones (el análogo a en este
contexto):
-- S es un tipo cualquiera (un conjunto).-- Q es un predicado que toma dos elementos de S y devuelve una proposición.def propiedad {S : Type} (Q : S -> S -> Prop) -- La hipótesis: para todo x, y en S, Q x y es verdadero. (h : forall x y : S, Q x y) -- La conclusión: para todo u en S, Q u u es verdadero. : (forall u : S, Q u u) :=
-- La prueba: dado un u, se usa la hipótesis 'h' con 'u' dos veces. fun u : S => h u uEn este ejemplo, fun cumple el papel del operador ; es la forma rápida de Lean
para decir: «toma un y devuelve ». Así, fun u : S => h u u:
- Introduce la variable (equivale a escribir ).
- Construye el resultado aplicando la hipótesis global al par .
- Devuelve esa prueba, produciendo la función
En otras palabras, en la función propiedad la palabra clave fun define la función que
transforma la hipótesis general « vale para todos los pares» en la versión específica
« vale para ». Se le puede pedir a Lean que verifique el tipo de la definición,
confirmando que coincide exactamente con la propiedad que se quería demostrar:
#check propiedad-- Lean responde:-- propiedad {S : Type} (Q : S -> S -> Prop)-- : (forall (x y : S), Q x y) -> forall (u : S), Q u uTambién se podría haber usado la notación de teorema, que simplifica la escritura y se explorará más adelante:
theorem propiedad {S : Type} (Q : S → S → Prop) : (forall x y, Q x y) → forall u, Q u u :=by intro h u exact h u uEste ejemplo es la esencia de : el tipo de la prueba depende del término . La prueba misma es una función que, dado un término , produce una demostración específica de . Esto materializa la capacidad de los tipos de depender de los términos, que es la contribución fundamental de este sistema.
Con las tres dependencias sobre la mesa (, y ), la página siguiente las organiza en una sola figura: el cubo de Barendregt.