Estoy experimentando con sistemas de tipo puro en el cubo lambda de Barendregt, específicamente con el más poderoso, el cálculo de construcciones. Este sistema tiene géneros *y BOX. Solo para el registro, a continuación estoy usando la sintaxis concreta de la Morteherramienta https://github.com/Gabriel439/Haskell-Morte-Library que está cerca del cálculo lambda clásico.
Veo que podemos emular tipos inductivos mediante algún tipo de codificación similar a la Iglesia (también conocido como isomorfismo Boehm-Berarducci para tipos de datos algebraicos). Para un ejemplo simple, uso type Bool = ∀(t : *) -> t -> t -> tcon los constructores True = λ(t : *) -> λ(x : t) -> λ(y : t) -> xy False = λ(t : *) -> λ(x : t) -> λ(y : t) -> y.
Veo que el tipo de funciones de nivel de término Bool -> Tes isomorfo a pares de tipos Product T Tcon Product = λ(A : *) -> λ(B : *) -> ∀(t : *) -> (A -> B -> t) -> tparamétrica de módulo clásico por medio de una función if : Bool -> λ(t : *) -> t -> t -> tque en realidad es identidad.
Todas las preguntas a continuación serán sobre representaciones de tipos dependientes Bool -> *.
Me puedo dividir
D : Bool -> *en par deD TrueyD False. ¿Existe la forma canónica de crear deDnuevo? Quiero reproducir el isomosfismoBool -> T = Product T Tmediante un análogo de funciónifa nivel de tipo, pero no puedo escribir esta función tan simple como originalifporque no podemos pasar tipos en argumentos como tipos.Utilizo una especie de tipo inductivo con dos constructores para resolver la pregunta (1). La descripción de alto nivel (estilo Agda) es el siguiente tipo (se utiliza en lugar del nivel de tipo
if)data BoolDep (T : *) (F : *) : Bool -> * where DepTrue : T -> BoolDep T F True DepFalse : F -> BoolDep T F Falsecon la siguiente codificación en PTS / CoC:
λ(T : *) -> λ(F : *) -> λ(bool : Bool ) -> ∀(P : Bool -> *) -> ∀(DepTrue : T -> P True ) -> ∀(DepFalse : F -> P False ) -> P bool¿Mi codificación anterior es correcta?
Puedo escribir los constructores de
BoolDepeste código paraDepTrue : ∀(T : *) -> ∀(F : *) -> T -> BoolDep T F True:λ(T : *) -> λ(F : *) -> λ(arg : T ) -> λ(P : Bool -> *) -> λ(DepTrue : T -> P True ) -> λ(DepFalse : F -> P False ) -> DepTrue arg
pero no puedo escribir la función inversa (o cualquier función en la dirección inversa). ¿Es posible? ¿O debería usar otra representación para BoolDepproducir un isomorfismo BoolDep T F True = T?
fuente

Respuestas:
No puede hacer esto usando la codificación tradicional de la Iglesia para
Bool:... porque no puedes escribir una función (útil) de tipo:
La razón por la cual, como notó, es que no puede pasar
*como primer argumento#Bool, lo que a su vez significa que los argumentosTrueyFalsepueden no ser tipos.Hay al menos tres formas de resolver esto:
Usa el cálculo de construcciones inductivas. Entonces podría generalizar el tipo de
#Boola:... y entonces sería una instancia
na1, que significa que podría pasar*₀como segundo argumento, lo que escriba-cheque porque:... entonces podría usar
#Boolpara seleccionar entre dos tipos.Agregue un tipo más:
Entonces definirías un
#Bool₂tipo separado como este:Este es esencialmente un caso especial del cálculo de las construcciones inductivas, pero produce un código menos reutilizable ya que ahora debemos mantener dos definiciones separadas
#Bool, una para cada tipo que deseamos admitir.Codificar
#Bool₂directamente dentro del cálculo de construcciones como:Si el objetivo es usar esto directamente sin modificar
morte, solo funcionará el enfoque n. ° 3.fuente
#Bool₁a#Bool₂