Eine Möglichkeit, Typen als Logik zu interpretieren, sind die Existenzbedingungen für Werte des Rückgabetyps. Also f :: a -> [a]
wir den Satz , daß, wenn es einen Wert vom Typ existiert a
, gibt einen Wert vom Typ existiert [a]
. Die Implementierung der Funktion ist der Beweis des Satzes.
Hier ist eine detailliertere Erklärung:
Grundsätzlich können wir mit Datenkonstruktoren ähnliche Dinge wie Summen und Produkte (ODER und UND) erstellen, aber wir können mehrere Varianten haben und den Typ speziell mit einem Namen "kennzeichnen", um ihn zu unterscheiden (wie den Namen List
).
Sie lassen uns sie auch rekursiv bauen: für einen Satz ein, der Satz [ a ] kann als Lösung der Gleichung angesehen werden
x ( a )⟺⊤ ∨ ( a ∧ x ( a ) )
Die Dinge werden etwas klarer, wenn Sie die Definition von List mit einem Pseudocode im GADT-Stil schreiben, ähnlich dem, was Sie in Agda sehen würden:
data List : Type -> Type where
Nil : ∀ a . List a
Cons : ∀ a . a -> List a -> List a
Dies gibt uns zwei Dinge: die Konstruktoren (oder Funktionen), die als Axiome für die Sätze von dienen List
, und Axiome für die Musteranpassung oder Dekonstruktion.
Grob gesagt werden die folgenden Axiome in die Logik eingeführt:
- Für jeden Vorschlag ein, [ a ] hält.
- Wenn ein hält, und [ a ] hält dann [ a ] hält
- Wenn [ a ] gilt dann auch nicht ⊤ hält, oder a ∧ [ a ] hält.
Diese sind ziemlich nutzlos, wenn sie als Logik interpretiert werden, da wir es immer wissen ⊤ hält, dort zu dekonstruieren gibt uns nicht viele nützliche Informationen
Ohne Quantifizierer oder leistungsfähigere Typerweiterungen (GADTs, Typfamilien, abhängige Typen usw.) können Sie feststellen, dass wir interessante Dinge nicht wirklich beweisen können, weshalb Sie häufig nicht viel über die Interpretation von Standard-Haskell-Typen als Logik sehen .