Tipi dipendenti dal tipo con codifica Church in PTS / CoC


11

Sto sperimentando sistemi di tipo puro nel cubo lambda di Barendregt, in particolare con il più potente, il Calculus of Constructions. Questo sistema ha specie *e BOX. Per la cronaca, di seguito sto usando la sintassi concreta dello Mortestrumento https://github.com/Gabriel439/Haskell-Morte-Library che è vicino al classico calcolo lambda.

Vedo che possiamo emulare tipi induttivi mediante una sorta di codifica simile alla Chiesa (alias isomorfismo di Boehm-Berarducci per tipi di dati algebrici). Per un semplice esempio uso tipo Bool = ∀(t : *) -> t -> t -> tcon i costruttori True = λ(t : *) -> λ(x : t) -> λ(y : t) -> xe False = λ(t : *) -> λ(x : t) -> λ(y : t) -> y.

Vedo che il tipo di funzioni a livello di termine Bool -> Tè isomorfo per coppie di tipi Product T Tcon Product = λ(A : *) -> λ(B : *) -> ∀(t : *) -> (A -> B -> t) -> tparametricità modulo classica per mezzo di una funzione if : Bool -> λ(t : *) -> t -> t -> tche è in realtà identità.

Tutte le domande che seguono saranno sulle rappresentazioni di tipi dipendenti Bool -> *.

  1. Posso dividere D : Bool -> *in coppia di D Truee D False. Esiste il modo canonico per creare di Dnuovo? Voglio riprodurre l'isomosfismo Bool -> T = Product T Tda un analogo della funzione ifa livello di tipo, ma non posso scrivere questa funzione tanto semplice quanto originale ifperché non possiamo passare i tipi in argomenti come i tipi.

  2. Uso una specie di tipo induttivo con due costruttori per risolvere la domanda (1). La descrizione di alto livello (stile Agda) è il seguente tipo (utilizzato anziché a livello di tipo if)

    data BoolDep (T : *) (F : *) : Bool -> * where
      DepTrue : T -> BoolDep T F True
      DepFalse : F -> BoolDep T F False
    

    con la seguente codifica in PTS / CoC:

    λ(T : *) -> λ(F : *) -> λ(bool : Bool ) ->
    ∀(P : Bool -> *) ->
    ∀(DepTrue : T -> P True ) ->
    ∀(DepFalse : F -> P False ) ->
    P bool
    

    La mia codifica sopra è corretta?

  3. Posso scrivere i costruttori BoolDepcome questo codice per DepTrue : ∀(T : *) -> ∀(F : *) -> T -> BoolDep T F True:

    λ(T : *) ->  λ(F : *) ->  λ(arg : T ) ->
    λ(P : Bool -> *) ->
    λ(DepTrue : T -> P True ) ->
    λ(DepFalse : F -> P False ) ->
    DepTrue arg
    

ma non riesco a scrivere la funzione inversa (o nessuna funzione nella direzione inversa). È possibile? O dovrei usare un'altra rappresentazione per BoolDepprodurre un isomorfismo BoolDep T F True = T?


Product T TBoolTBoolT((t:)(ttt))TProductTT(t:)((TTt)t)

@Giorgio Mossa vedi cstheory.stackexchange.com/questions/30923/… - se hai parametricità (non in tutti i modelli ma in quello iniziale (sintattico)) allora hai l'isomorfismo.
ZeitRaffer,

Risposte:


9

Non puoi farlo usando la tradizionale codifica Church per Bool:

#Bool = ∀(Bool : *) → ∀(True : Bool) → ∀(False : Bool) → Bool

... perché non puoi scrivere una (utile) funzione di tipo:

#Bool → *

Il motivo per cui, come hai notato, è che non puoi passare *come primo argomento #Bool, il che a sua volta significa che gli argomenti Truee Falsepotrebbero non essere tipi.

Esistono almeno tre modi per risolvere questo problema:

  1. Usa il calcolo delle costruzioni induttive. Quindi puoi generalizzare il tipo di #Boola:

    #Bool = ∀(n : Nat) → ∀(Bool : *ₙ) → ∀(True : Bool) → ∀(False : Bool) → Bool
    

    ... e poi si sarebbe istanziare na 1, che significa che potrebbe passare *₀come secondo argomento, che sarebbe di tipo-controllo perché:

    *₀ : *₁
    

    ... quindi è possibile utilizzare #Boolper selezionare tra due tipi.

  2. Aggiungi un altro ordinamento:

    * : □ : △
    

    Quindi definiresti un #Bool₂tipo separato come questo:

    #Bool₂ = ∀(Bool : □) → ∀(True : Bool) → ∀(False : Bool) → Bool
    

    Questo è essenzialmente un caso speciale del calcolo delle costruzioni induttive, ma produce un codice meno riutilizzabile poiché ora dobbiamo mantenere due definizioni separate #Bool, una per ogni tipo che desideriamo supportare.

  3. Codifica #Bool₂direttamente nel calcolo delle costruzioni come:

    #Bool₂ = ∀(True : *) → ∀(False : *) → *
    

Se l'obiettivo è utilizzarlo direttamente all'interno di unmodified, funzionerà mortesolo l'approccio n. 3.


Come posso vedere, non possiamo convertire # Bool₁ -> # Bool₂, no?
ZeitRaffer,

@ZeitRaffer Proprio così. Non puoi convertire da #Bool₁in#Bool₂
Gabriel Gonzalez,

1
Hmm ... IIUC, si chiama "Calcolo delle costruzioni induttive" un calcolo con una gerarchia infinita di tipi, ma AFAIK il CIC originale non aveva una cosa del genere (ha aggiunto solo tipi induttivi al CoC). Potresti pensare all'ECC di Luo (calcolo esteso delle costruzioni)?
Stefan
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.