Ich experimentiere mit reinen Typsystemen in Barendregts Lambda-Würfel, speziell mit dem mächtigsten, dem Calculus of Constructions. Dieses System hat Sorten *
und BOX
. Nur zur Veranschaulichung: Im Folgenden verwende ich die konkrete Syntax des Morte
Tools https://github.com/Gabriel439/Haskell-Morte-Library, das dem klassischen Lambda-Kalkül nahe kommt.
Ich sehe, wir können induktive Typen durch eine Art kirchenähnliche Codierung emulieren (auch bekannt als Boehm-Berarducci-Isomorphismus für algebraische Datentypen). Für ein einfaches Beispiel verwende ich type Bool = ∀(t : *) -> t -> t -> t
mit den Konstruktoren True = λ(t : *) -> λ(x : t) -> λ(y : t) -> x
und False = λ(t : *) -> λ(x : t) -> λ(y : t) -> y
.
Ich sehe, dass der Typ der Funktionen auf Bool -> T
Termebene zu Typpaaren Product T T
mit klassischer Product = λ(A : *) -> λ(B : *) -> ∀(t : *) -> (A -> B -> t) -> t
Modulo-Parametrizität mittels einer Funktion, if : Bool -> λ(t : *) -> t -> t -> t
die tatsächlich Identität ist, isomorph ist.
Alle folgenden Fragen beziehen sich auf Darstellungen abhängiger Typen Bool -> *
.
Ich kann mich
D : Bool -> *
in ein Paar vonD True
und aufteilenD False
. Gibt es den kanonischen Weg,D
wieder zu schaffen ? Ich möchte den IsomosphismusBool -> T = Product T T
durch ein Analogon der Funktionif
auf Typebene reproduzieren, aber ich kann diese Funktion nicht so einfach wie das Original schreiben,if
da wir keine Arten in Argumenten wie Typen übergeben können.Ich benutze eine Art induktiven Typ mit zwei Konstruktoren, um Frage (1) zu lösen. Die Beschreibung auf hoher Ebene (Agda-Stil) ist der folgende Typ (anstelle von Typ-Ebene verwendet
if
)data BoolDep (T : *) (F : *) : Bool -> * where DepTrue : T -> BoolDep T F True DepFalse : F -> BoolDep T F False
mit der folgenden Codierung in PTS / CoC:
λ(T : *) -> λ(F : *) -> λ(bool : Bool ) -> ∀(P : Bool -> *) -> ∀(DepTrue : T -> P True ) -> ∀(DepFalse : F -> P False ) -> P bool
Ist meine obige Kodierung korrekt?
Ich kann die Konstruktoren für
BoolDep
diesen Code aufschreiben fürDepTrue : ∀(T : *) -> ∀(F : *) -> T -> BoolDep T F True
:λ(T : *) -> λ(F : *) -> λ(arg : T ) -> λ(P : Bool -> *) -> λ(DepTrue : T -> P True ) -> λ(DepFalse : F -> P False ) -> DepTrue arg
aber ich kann die Umkehrfunktion (oder irgendeine Funktion in der Umkehrrichtung) nicht aufschreiben. Ist es möglich? Oder sollte ich eine andere Darstellung verwenden BoolDep
, um einen Isomorphismus zu erzeugen BoolDep T F True = T
?
quelle
Antworten:
Sie können dies nicht mit der traditionellen Kirchencodierung tun für
Bool
:... weil Sie keine (nützliche) Funktion vom Typ schreiben können:
Der Grund dafür ist, wie Sie bemerkt haben, dass Sie nicht
*
als erstes Argument an übergeben können#Bool
, was wiederum bedeutet, dass die ArgumenteTrue
undFalse
möglicherweise keine Typen sind.Es gibt mindestens drei Möglichkeiten, wie Sie dies lösen können:
Verwenden Sie die Berechnung der induktiven Konstruktionen. Dann könnten Sie den Typ von verallgemeinern
#Bool
:... und dann würden Sie instanziiert
n
zu1
, was bedeutet , Sie passieren könnte*₀
als das zweite Argument, das würde Typprüfung , weil:... also können Sie
#Bool
zwischen zwei Typen wählen.Fügen Sie eine weitere Sorte hinzu:
Dann würden Sie einen separaten
#Bool₂
Typ wie folgt definieren :Dies ist im Wesentlichen ein Sonderfall der Berechnung induktiver Konstruktionen, erzeugt jedoch weniger wiederverwendbaren Code, da wir jetzt zwei separate Definitionen von pflegen müssen
#Bool
, eine für jede Sorte, die wir unterstützen möchten.Codieren Sie
#Bool₂
direkt in der Konstruktionsrechnung als:Wenn das Ziel darin besteht, dies direkt in unverändert zu verwenden,
morte
funktioniert nur Ansatz 3.quelle
#Bool₁
zu konvertieren#Bool₂