Nivel 6 · El CIC y Lean
Tipos inductivos
El CIC es una extensión del CoC que resuelve los problemas de la página anterior añadiendo una herramienta fundamental: la capacidad de definir tipos inductivos de forma nativa. En lugar de codificar los números naturales, simplemente se los declara especificando sus reglas de construcción: un conjunto con dos constructores,
- un constructor para el cero: , y
- una función sucesor: .
Esta simpleza le da al sistema toda la información que necesita. El CIC entiende que un natural es, o bien , o bien el de otro natural, y nada más. A partir de esta definición, el sistema genera automáticamente las herramientas de razonamiento y cómputo asociadas (la página siguiente las estudia en detalle). El desarrollo formal sigue el artículo de Paulin-Mohring Paulin-Mohring (1993) .
De la intuición al formalismo: gramática y convenciones
Para enunciar las reglas con precisión se adopta la notación de los Sistemas de Tipos Generalizados (GTS), también llamados Pure Type Systems (PTS) (Paulin-Mohring, 1993) . La sintaxis abstracta de términos es
donde recorre el conjunto de sorts. Se usan las convenciones estándar:
- Producto dependiente: denota .
- Abstracción: denota .
- Flecha como caso particular: si , se escribe .
- Asociatividad: la flecha asocia a la derecha, la aplicación a la izquierda.
- Sustitución: es la sustitución de por las ocurrencias libres de en .
El símbolo proviene de la notación BNF y define reglas de producción sintáctica; no debe confundirse con la igualdad matemática. Un tratamiento detallado de los GTS puede encontrarse en Barendregt (1991) . La página sobre universos volverá sobre las sorts; por ahora basta leer como «la sort de los tipos de datos».
Aridades y formas de constructor
Una aridad de una sort describe la forma del tipo inductivo que se va a definir. Se genera por la gramática
Por ejemplo, la aridad de es , mientras que la de las listas (parametrizadas por un tipo) es (Paulin-Mohring, 1993) .
Lean no usa la palabra aridad; su documentación describe la firma del constructor de tipo como una secuencia de argumentos (un «telescopio»): primero los parámetros, después los índices, y al final la sort de retorno. En particular, List tiene firma y Fin tiene :
#check List -- : Type u → Type u -- parámetro α#check Fin -- : Nat → Type -- parámetro nLa firma externa Nat → Type no distingue entre parámetro e índice; la diferencia está en la definición. Un parámetro aparece uniformemente a la izquierda de los dos puntos en toda la declaración: en Lean 4, el argumento de Fin es un parámetro. Un índice genuino, en cambio, es fijado por cada constructor en su conclusión: el ejemplo canónico es el segundo argumento de Eq : α → α → Prop, que el constructor Eq.refl a instancia en a. Los parámetros son constantes a lo largo de la definición; los índices varían con cada constructor.
Sea una aridad y una variable de tipo . Un tipo es estrictamente positivo con respecto a si no aparece a la izquierda de ninguna flecha , a ninguna profundidad de anidamiento. Un tipo estrictamente positivo bien formado puede escribirse como , con la restricción de que no aparece libremente en ningún término de ni de .
La notación vectorial denota secuencias finitas, posiblemente vacías: abrevia , y es la aplicación de a argumentos , cuya longitud viene dada por la aridad de .
La condición es estrictamente más fuerte que prohibir las posiciones contravariantes: en la ocurrencia de es covariante (dos inversiones) y, sin embargo, el tipo no es estrictamente positivo; en presencia de impredicatividad, admitir tales tipos también compromete la consistencia. La razón de fondo es la siguiente: si se admitiera una ocurrencia negativa, por ejemplo un constructor de tipo , se podría fabricar un punto fijo y, con él, un habitante de , reproduciendo dentro del sistema de tipos la paradoja de Russell. La positividad estricta es la barrera que lo impide.
Sea una aridad y una variable de tipo . Un término es una forma de constructor con respecto a si es un tipo cuya conclusión es y donde todas las ocurrencias de en los tipos de sus argumentos son estrictamente positivas.
Por ejemplo, en la definición de los naturales, la aridad es y una variable de tipo ; los tipos de los constructores son (para ) y (para ). Ambos son formas de constructor válidas. Los constructores realizan la introducción del tipo inductivo. En Lean:
#check Nat.zero -- Nat#check Nat.succ -- Nat → Nat#check List.nil -- List α#check List.cons -- α → List α → List αLas reglas de formación e introducción
Se introducen nuevos pseudo-términos para representar las definiciones inductivas y sus constructores. Conviene subrayar que , y son pseudo-términos de Paulin-Mohring
(Paulin-Mohring, 1993)
para describir la maquinaria interna del núcleo; no son sintaxis de Lean: allí se realizan con la palabra clave inductive (formación), los nombres de los constructores (introducción) y el eliminador .rec que el sistema genera.
Formación (Ind). Se introduce el constructor de términos . Si es una aridad de y cada es una forma de constructor de bien tipada en la sort (bajo el supuesto ), el tipo inductivo está bien formado y tiene tipo :
El símbolo actúa como separador sintáctico de la lista de constructores; semánticamente denota que el tipo inductivo es una unión disjunta generada por estas reglas: un término habita el tipo si fue construido mediante o … o .
Para definir el tipo de los números naturales se utiliza la aridad . La variable representa al propio tipo dentro de la definición.
- El constructor del cero tiene tipo , que se escribe formalmente como .
- El constructor del sucesor tiene tipo , que se escribe formalmente como .
Por lo tanto, la definición formal es
Esto ilustra cómo el separador distingue entre el caso base (cero) y el caso recursivo (sucesor).
Introducción (Constr). Para cada tipo inductivo se introducen términos , con . La regla de tipado asigna a cada constructor el tipo de su especificación, sustituyendo la variable abstracta por el propio tipo inductivo :
En Lean, la declaración correspondiente es directa y el paralelismo con el formalismo es exacto:
inductive Nat where | zero : Nat | succ : Nat → Nat
inductive List (α : Type u) where | nil : List α | cons : α → List α → List αCon la formación y la introducción en la mano, falta la pieza que dota al sistema de poder lógico y computacional: el principio de eliminación, tema de la página siguiente.