Abhängige Typentheorie und 'beliebige' Typfunktionen
Meine erste Antwort auf diese Frage war reich an Konzepten und wenig an Details und reflektierte die Unterfrage: "Was ist los?". Diese Antwort ist dieselbe, konzentriert sich jedoch auf die Unterfrage "Können wir beliebige Typfunktionen erhalten?".
Eine Erweiterung der algebraischen Operationen von Summen- und Produkt sind die sogenannten "großen Betreiber, die die Summe und Produkt einer Sequenz darstellen (oder allgemeiner, der Summe und Produkt einer Funktion über eine Domäne) in der Regel geschrieben Σ
und Π
jeweils. Siehe Sigma-Notation .
Also die Summe
a₀ + a₁X + a₂X² + ...
könnte geschrieben werden
Σ[i ∈ ℕ]aᵢXⁱ
Wo a
ist zum Beispiel eine Folge von reellen Zahlen. Das Produkt würde ähnlich mit Π
statt dargestellt Σ
.
Wenn Sie aus der Ferne schauen, ähnelt diese Art von Ausdruck einer 'willkürlichen' Funktion in X
; Wir beschränken uns natürlich auf ausdrucksstarke Reihen und die damit verbundenen analytischen Funktionen. Ist dies ein Kandidat für eine Darstellung in einer Typentheorie? Bestimmt!
Die Klasse der Typentheorien, die diese Ausdrücke unmittelbar darstellen, ist die Klasse der 'abhängigen' Typentheorien: Theorien mit abhängigen Typen. Natürlich haben wir Begriffe, die von Begriffen abhängig sind, und in Sprachen wie Haskell mit Typfunktionen und Typquantifizierung, Begriffen und Typen, die von Typen abhängen. In einer abhängigen Einstellung haben wir zusätzlich Typen, die von Begriffen abhängen. Haskell ist keine abhängig typisierte Sprache, obwohl viele Merkmale abhängiger Typen simuliert werden können, indem die Sprache ein wenig gefoltert wird .
Curry-Howard und abhängige Typen
Der 'Curry-Howard-Isomorphismus' begann sein Leben als Beobachtung, dass die Begriffe und Typbeurteilungsregeln des einfach getippten Lambda-Kalküls genau der natürlichen Deduktion (wie von Gentzen formuliert) entsprechen, die auf die intuitionistische Aussagenlogik angewendet wird, wobei Typen die Sätze ersetzen und Begriffe, die den Platz von Beweisen einnehmen, obwohl die beiden unabhängig voneinander erfunden / entdeckt wurden. Seitdem ist es eine große Inspirationsquelle für Typentheoretiker. Eines der offensichtlichsten zu berücksichtigenden Dinge ist, ob und wie diese Entsprechung für die Aussagenlogik auf Prädikatenlogiken oder Logiken höherer Ordnung erweitert werden kann. Aus diesem Forschungsweg entstanden zunächst abhängige Typentheorien.
Eine Einführung in den Curry-Howard-Isomorphismus für einfach typisierte Lambda-Berechnungen finden Sie hier . Wenn wir zum Beispiel beweisen wollen, A ∧ B
müssen wir beweisen A
und beweisen B
; Ein kombinierter Beweis ist einfach ein Beweispaar: einer für jede Konjunktion.
In natürlicher Ableitung:
Γ ⊢ A Γ ⊢ B
Γ ⊢ A ∧ B
und in einfach getippter Lambda-Rechnung:
Γ ⊢ a : A Γ ⊢ b : B
Γ ⊢ (a, b) : A × B
Ähnliche Entsprechungen existieren für ∨
und Summentypen →
und Funktionstypen und die verschiedenen Eliminierungsregeln.
Ein unbeweisbarer (intuitionistisch falscher) Satz entspricht einem unbewohnten Typ.
Unter Berücksichtigung der Analogie von Typen als logische Sätze können wir uns überlegen, wie Prädikate in der Typwelt modelliert werden können. Es gibt viele Möglichkeiten, wie dies formalisiert wurde (siehe diese Einführung zu Martin-Löfs Intuitionistischer Typentheorie für einen weit verbreiteten Standard), aber der abstrakte Ansatz beobachtet normalerweise, dass ein Prädikat wie ein Satz mit Variablen für freie Begriffe oder alternativ wie ein Satz ist eine Funktion, die sich auf Sätze bezieht. Wenn wir zulassen, dass Typausdrücke Begriffe enthalten, bietet sich sofort eine Behandlung im Lambda-Kalkül-Stil an!
Was ist ein Beweis für nur konstruktive Beweise ∀x ∈ X.P(x)
? Wir können es uns als Beweisfunktion vorstellen, indem wir Begriffe ( x
) für Beweise ihrer entsprechenden Sätze verwenden ( P(x)
). So Mitglieder (Proofs) des Typs (Satz) ∀x : X.P(x)
sind ‚abhängige Funktionen‘, die für jeden x
in X
einer Laufzeit von Art geben P(x)
.
Was ist mit ∃x ∈ X.P(x)
? Wir brauchen jedes Mitglied X
, x
zusammen mit einem Beweis P(x)
. Mitglieder (Beweise) des Typs (Satzes) ∃x : X.P(x)
sind also 'abhängige Paare': ein definierter Begriff x
in X
, zusammen mit einem Begriff des Typs P(x)
.
Notation: Ich werde verwenden
∀x ∈ X...
für tatsächliche Aussagen über Mitglieder der Klasse X
, und
∀x : X...
für Typausdrücke, die einer universellen Quantifizierung über Typ entsprechen X
. Ebenso für ∃
.
Kombinatorische Überlegungen: Produkte und Summen
Neben der Curry-Howard-Entsprechung von Typen mit Sätzen haben wir die kombinatorische Entsprechung von algebraischen Typen mit Zahlen und Funktionen, was der Hauptpunkt dieser Frage ist. Glücklicherweise kann dies auf die oben beschriebenen abhängigen Typen erweitert werden!
Ich werde die Modulnotation verwenden
|A|
die 'Größe' eines Typs darstellen A
, die in der Frage skizzierte Entsprechung zwischen Typen und Zahlen explizit machen. Beachten Sie, dass dies ein Konzept außerhalb der Theorie ist. Ich behaupte nicht, dass es einen solchen Operator in der Sprache geben muss.
Zählen wir die möglichen (vollständig reduzierten, kanonischen) Mitglieder des Typs
∀x : X.P(x)
Dies ist die Art von abhängigen Funktionen, die Begriffe x
von Typ X
zu Begriffen von Typ nehmen P(x)
. Jede solche Funktion muss für jeden Term eine Ausgabe haben X
, und diese Ausgabe muss von einem bestimmten Typ sein. Für jeden x
in X
, dann gibt dieser |P(x)|
‚Wahl‘ der Ausgabe.
Die Pointe ist
|∀x : X.P(x)| = Π[x : X]|P(x)|
Das macht natürlich keinen großen Sinn, X
ist IO ()
aber auf algebraische Typen anwendbar.
Ebenso ein Begriff vom Typ
∃x : X.P(x)
ist die Art der Paare (x, p)
mit p : P(x)
, so gegebenen jede x
in X
können wir ein geeignetes Paar mit einem Mitglied des Konstrukts P(x)
, was |P(x)|
‚Auswahl‘.
Daher,
|∃x : X.P(x)| = Σ[x : X]|P(x)|
mit den gleichen Einschränkungen.
Dies rechtfertigt die gemeinsame Notation für abhängige Typen in Theorien unter Verwendung der Symbole Π
und Σ
, und tatsächlich verwischen viele Theorien die Unterscheidung zwischen "für alle" und "Produkt" und zwischen "es gibt" und "Summe" aufgrund der oben erwähnten Entsprechungen.
Wir kommen näher!
Vektoren: Repräsentieren abhängiger Tupel
Können wir jetzt numerische Ausdrücke wie codieren?
Σ[n ∈ ℕ]Xⁿ
als Typausdrücke?
Nicht ganz. Während wir informell die Bedeutung von Ausdrücken wie Xⁿ
in Haskell betrachten können, wo X
es sich um einen Typ und n
eine natürliche Zahl handelt, handelt es sich um einen Missbrauch der Notation. Dies ist ein Typausdruck, der eine Zahl enthält: eindeutig kein gültiger Ausdruck.
Bei abhängigen Typen im Bild sind Typen mit Zahlen genau der Punkt. In der Tat sind abhängige Tupel oder 'Vektoren' ein sehr häufig genanntes Beispiel dafür, wie abhängige Typen pragmatische Sicherheit auf Typebene für Operationen wie den Listenzugriff bieten können . Ein Vektor ist nur eine Liste mit Informationen auf Typebene bezüglich seiner Länge: genau das, wonach wir für Typausdrücke wie suchen Xⁿ
.
Für die Dauer dieser Antwort lassen Sie
Vec X n
sein , die Art von längen- n
Vektoren X
; -Typ - Werten.
Technisch gesehen ist n
hier eher als eine tatsächliche natürliche Zahl eine Darstellung einer natürlichen Zahl im System. Wir können natürliche Zahlen ( Nat
) im Peano-Stil entweder als Null ( 0
) oder als Nachfolger ( S
) einer anderen natürlichen Zahl darstellen, und n ∈ ℕ
ich schreibe ˻n˼
den Begriff, in Nat
dem dargestellt wird n
. Zum Beispiel ˻3˼
ist S (S (S 0))
.
Dann haben wir
|Vec X ˻n˼| = |X|ⁿ
für jeden n ∈ ℕ
.
Nat-Typen: Förderung von ℕ Begriffen zu Typen
Jetzt können wir Ausdrücke wie codieren
Σ[n ∈ ℕ]Xⁿ
als Typen. Dieser spezielle Ausdruck würde zu einem Typ führen, der natürlich isomorph zu dem Typ von Listen von ist X
, wie in der Frage angegeben. (Nicht nur das, sondern aus kategorietheoretischer Sicht ist die Typfunktion - die ein Funktor ist -, X
die den obigen Typ übernimmt , natürlich isomorph zum Listenfunktor.)
Ein letztes Puzzleteil für 'beliebige' Funktionen ist das Codieren, z
f : ℕ → ℕ
Ausdrücke wie
Σ[n ∈ ℕ]f(n)Xⁿ
damit wir beliebige Koeffizienten auf eine Potenzreihe anwenden können.
Wir verstehen bereits die Entsprechung algebraischer Typen mit Zahlen, sodass wir von Typen zu Zahlen und von Typfunktionen zu numerischen Funktionen abbilden können. Wir können auch den anderen Weg gehen! - Wenn man eine natürliche Zahl nimmt, gibt es offensichtlich einen definierbaren algebraischen Typ mit so vielen Termmitgliedern, unabhängig davon, ob wir abhängige Typen haben oder nicht. Wir können dies leicht außerhalb der Typentheorie durch Induktion beweisen . Was wir brauchen, ist eine Möglichkeit, innerhalb des Systems von natürlichen Zahlen auf Typen abzubilden .
Eine erfreuliche Erkenntnis ist, dass, sobald wir abhängige Typen haben, der Beweis durch Induktion und die Konstruktion durch Rekursion sehr ähnlich werden - tatsächlich sind sie in vielen Theorien dasselbe. Sollten wir sie nicht konstruieren können, da wir durch Induktion beweisen können, dass Typen existieren, die unsere Bedürfnisse erfüllen?
Es gibt verschiedene Möglichkeiten, Typen auf Begriffebene darzustellen. Ich werde hier eine imaginäre Haskellish-Notation mit *
für das Universum der Typen verwenden, die normalerweise selbst als Typ in einer abhängigen Umgebung betrachtet wird. 1
Ebenso gibt es mindestens so viele Möglichkeiten, " ℕ
-elimination" zu notieren , wie es abhängige Typentheorien gibt. Ich werde eine Haskellish Pattern Matching Notation verwenden.
Wir brauchen eine Zuordnung α
von Nat
bis *
zur Eigenschaft
∀n ∈ ℕ.|α ˻n˼| = n.
Die folgende Pseudodefinition reicht aus.
data Zero -- empty type
data Successor a = Z | Suc a -- Successor ≅ Maybe
α : Nat -> *
α 0 = Zero
α (S n) = Successor (α n)
Wir sehen also, dass die Wirkung von α
das Verhalten des Nachfolgers S
widerspiegelt und es zu einer Art Homomorphismus macht. Successor
ist eine Typfunktion, die der Anzahl der Mitglieder eines Typs 'eins' hinzufügt; das heißt, |Successor a| = 1 + |a|
für alle a
mit einer definierten Größe.
Zum Beispiel α ˻4˼
(was ist α (S (S (S (S 0))))
), ist
Successor (Successor (Successor (Successor Zero)))
und die Begriffe dieses Typs sind
Z
Suc Z
Suc (Suc Z)
Suc (Suc (Suc Z))
Geben Sie uns genau vier Elemente : |α ˻4˼| = 4
.
Ebenso n ∈ ℕ
haben wir für jeden
|α ˻n˼| = n
nach Bedarf.
- Viele Theorien verlangen, dass die Mitglieder von
*
lediglich Repräsentanten von Typen sind, und eine Operation wird als explizite Zuordnung von Typbegriffen *
zu den zugehörigen Typen bereitgestellt . Andere Theorien erlauben es den Literaltypen selbst, Entitäten auf Termebene zu sein.
"Beliebige" Funktionen?
Jetzt haben wir den Apparat, eine vollständig allgemeine Potenzreihe als Typ auszudrücken!
Die Serie
Σ[n ∈ ℕ]f(n)Xⁿ
wird zum Typ
∃n : Nat.α (˻f˼ n) × (Vec X n)
Wo ˻f˼ : Nat → Nat
ist eine geeignete Darstellung in der Sprache der Funktion f
. Wir können dies wie folgt sehen.
|∃n : Nat.α (˻f˼ n) × (Vec X n)|
= Σ[n : Nat]|α (˻f˼ n) × (Vec X n)| (property of ∃ types)
= Σ[n ∈ ℕ]|α (˻f˼ ˻n˼) × (Vec X ˻n˼)| (switching Nat for ℕ)
= Σ[n ∈ ℕ]|α ˻f(n)˼ × (Vec X ˻n˼)| (applying ˻f˼ to ˻n˼)
= Σ[n ∈ ℕ]|α ˻f(n)˼||Vec X ˻n˼| (splitting product)
= Σ[n ∈ ℕ]f(n)|X|ⁿ (properties of α and Vec)
Wie "willkürlich" ist das? Wir beschränken uns bei dieser Methode nicht nur auf ganzzahlige Koeffizienten, sondern auch auf natürliche Zahlen. Abgesehen f
davon kann bei einer Turing Complete- Sprache mit abhängigen Typen alles möglich sein, und wir können jede analytische Funktion mit natürlichen Zahlenkoeffizienten darstellen.
Ich habe die Wechselwirkung davon zum Beispiel mit dem Fall nicht untersucht, der in der Frage angegeben wurde, List X ≅ 1/(1 - X)
oder welchen möglichen Sinn solche negativen und nicht ganzzahligen "Typen" in diesem Zusammenhang haben könnten.
Hoffentlich hilft diese Antwort dabei, herauszufinden, wie weit wir mit Funktionen beliebigen Typs gehen können.