Ich habe kürzlich einen Universitätskurs mit Haskell und Agda (einer abhängigen typisierten funktionalen Programmiersprache) abgeschlossen und mich gefragt, ob es möglich ist, Lambda-Kalkül in diesen durch kombinatorische Logik zu ersetzen. Mit Haskell scheint dies mit den S- und K-Kombinatoren möglich zu sein, wodurch es punktfrei wird. Ich fragte mich, was das Äquivalent für Agda war. Kann man eine abhängig typisierte funktionale Programmiersprache erstellen, die Agda entspricht, ohne Variablen zu verwenden?
Ist es auch möglich, die Quantifizierung durch Kombinatoren zu ersetzen? Ich weiß nicht, ob dies ein Zufall ist, aber eine universelle Quantifizierung lässt beispielsweise eine Typensignatur wie einen Lambda-Ausdruck aussehen. Gibt es eine Möglichkeit, die universelle Quantifizierung aus einer Typensignatur zu entfernen, ohne ihre Bedeutung zu ändern? ZB in:
forall a : Int -> a < 0 -> a + a < a
Kann das Gleiche ohne Verwendung eines Foralls ausgedrückt werden?
Antworten:
Also habe ich ein bisschen mehr darüber nachgedacht und einige Fortschritte gemacht. Hier ist ein erster Versuch, Martin-Löfs wunderbar einfaches (aber inkonsistentes)
Set : Set
System in einem kombinatorischen Stil zu codieren . Es ist kein guter Weg, um fertig zu werden, aber es ist der einfachste Ort, um loszulegen. Die Syntax dieser Typentheorie ist nur Lambda-Kalkül mit Typanmerkungen, Pi-Typen und einer Universumsmenge.Die Zieltyp-Theorie
Der Vollständigkeit halber werde ich die Regeln vorstellen. Die Kontextgültigkeit besagt lediglich, dass Sie Kontexte aus leeren Kontexten erstellen können, indem Sie neue Variablen in
Set
s nebeneinander setzen .Und jetzt können wir sagen, wie man Typen für Begriffe in einem bestimmten Kontext synthetisiert und wie man den Typ von etwas bis zum Rechenverhalten der darin enthaltenen Begriffe ändert.
In einer kleinen Abweichung vom Original habe ich Lambda zum einzigen Bindungsoperator gemacht, daher sollte das zweite Argument von Pi eine Funktion sein, die berechnet, wie der Rückgabetyp von der Eingabe abhängt. Konventionell (z. B. in Agda, aber leider nicht in Haskell) erstreckt sich der Umfang von Lambda so weit wie möglich nach rechts, sodass Sie Abstraktionen oft ungebrochen lassen können, wenn sie das letzte Argument eines Operators höherer Ordnung sind: Sie können sehen, dass ich es getan habe das mit Pi. Ihr Agda-Typ
(x : S) -> T
wirdPi S \ x:S -> T
.( Exkurs . Typanmerkungen auf Lambda sind erforderlich, wenn Sie die Art der Abstraktionen synthetisieren möchten . Wenn Sie als Modusoperandi zur Typprüfung wechseln, benötigen Sie weiterhin Anmerkungen, um einen Beta-Redex wie zu überprüfen
(\ x -> t) s
, da Sie keine Möglichkeit haben Ich rate modernen Designern, die Typen zu überprüfen und Beta-Redexes von der Syntax auszuschließen.)( Exkurs . Dieses System ist inkonsistent, da
Set:Set
es die Kodierung einer Vielzahl von "Lügnerparadoxen" ermöglicht. Als Martin-Löf diese Theorie vorschlug, schickte Girard ihm eine Kodierung in seinem eigenen inkonsistenten System U. Das nachfolgende Paradoxon aufgrund von Hurkens ist das sauberste giftige Konstruktion, die wir kennen.)Kombinatorsyntax und Normalisierung
Wie auch immer, wir haben zwei zusätzliche Symbole, Pi und Set, so dass wir vielleicht eine kombinatorische Übersetzung mit S, K und zwei zusätzlichen Symbolen verwalten können: Ich habe U für das Universum und P für das Produkt gewählt.
Jetzt können wir die untypisierte kombinatorische Syntax (mit freien Variablen) definieren:
Beachten Sie, dass ich die Mittel zum Einbeziehen von freien Variablen, die durch den Typ dargestellt werden,
a
in diese Syntax aufgenommen habe. Abgesehen davon, dass es meinerseits ein Reflex ist (jede Syntax, die diesen Namen verdient, ist eine freie Monade mitreturn
Einbettungsvariablen und>>=
perfomierender Substitution), ist es praktisch, Zwischenstufen bei der Konvertierung von Begriffen mit Bindung an ihre kombinatorische Form darzustellen.Hier ist die Normalisierung:
(Eine Übung für den Leser besteht darin, einen Typ für genau die normalen Formen zu definieren und die Typen dieser Operationen zu schärfen.)
Darstellung der Typentheorie
Wir können jetzt eine Syntax für unsere Typentheorie definieren.
Ich verwende eine de Bruijn-Indexdarstellung in der Art von Bellegarde und Hook (wie von Bird und Paterson populär gemacht). Der Typ
Su a
hat ein Element mehr alsa
, und wir verwenden ihn als Typ der freien Variablen unter einem Ordner, wobeiZe
die neu gebundene VariableSu x
die verschobene Darstellung der alten freien Variablen istx
.Begriffe in Kombinatoren übersetzen
Und damit erwerben wir die übliche Übersetzung, basierend auf der Klammerabstraktion .
Typisierung der Kombinatoren
Die Übersetzung zeigt die Art und Weise, wie wir die Kombinatoren verwenden, was uns einen ziemlichen Hinweis darauf gibt, welche Typen sie haben sollten.
U
undP
sind nur Set-Konstruktoren, also sollten wir haben, wenn wir nicht übersetzte Typen schreiben und "Agda-Notation" für Pi zulassenDer
K
Kombinator wird verwendet, um einen Wert eines TypsA
gegenüber einem anderen Typ auf eine konstante Funktion zu hebenG
.Der
S
Kombinator wird verwendet, um Anwendungen über einen Typ zu heben, von dem alle Teile abhängen können.Wenn Sie sich den Typ von ansehen
S
, werden Sie feststellen, dass er genau die kontextualisierte Anwendungsregel der Typentheorie angibt. Daher ist er geeignet, das Anwendungskonstrukt widerzuspiegeln. Das ist seine Aufgabe!Wir haben dann nur Anwendung für geschlossene Sachen
Aber es gibt einen Haken. Ich habe die Typen der Kombinatoren in der gewöhnlichen Typentheorie geschrieben, nicht in der kombinatorischen Typentheorie. Zum Glück habe ich eine Maschine, die die Übersetzung macht.
Ein kombinatorisches Typsystem
Da haben Sie es also in all seiner unlesbaren Pracht: eine kombinatorische Darstellung von
Set:Set
!Es gibt immer noch ein kleines Problem. Die Syntax des Systems gibt Ihnen keine Möglichkeit , das zu erraten
G
,A
undB
Parameter fürS
und in ähnlicher Weise für dieK
, nur von den Bedingungen. Dementsprechend können wir Typisierungsableitungen algorithmisch überprüfen , aber wir können nicht einfach Kombinatorbegriffe typechecken, wie wir es mit dem ursprünglichen System könnten. Was möglicherweise funktioniert, besteht darin, dass die Eingabe in den Typechecker Typanmerkungen zu Verwendungen von S und K enthält, wodurch die Ableitung effektiv aufgezeichnet wird. Aber das ist eine andere Dose Würmer ...Dies ist ein guter Ort, um anzuhalten, wenn Sie scharf genug waren, um anzufangen. Der Rest ist "hinter den Kulissen".
Generieren der Kombinatortypen
Ich habe diese kombinatorischen Typen mithilfe der Klammerabstraktionsübersetzung aus den relevanten typentheoretischen Begriffen generiert. Um zu zeigen, wie ich es gemacht habe und um diesen Beitrag nicht ganz sinnlos zu machen, möchte ich meine Ausrüstung anbieten.
Ich kann die Typen der Kombinatoren, die vollständig über ihre Parameter abstrahiert sind, wie folgt schreiben. Ich benutze meine praktische
pil
Funktion, die Pi und Lambda kombiniert, um eine Wiederholung des Domänentyps zu vermeiden, und die es mir recht hilfreich ermöglicht, den Funktionsraum von Haskell zum Binden von Variablen zu verwenden. Vielleicht können Sie fast das Folgende lesen!Nachdem diese definiert wurden, extrahierte ich die relevanten offenen Subterme und führte sie durch die Übersetzung.
A de Bruijn Encoding Toolkit
Hier erfahren Sie, wie Sie bauen
pil
. Zunächst definiere ich eine Klasse vonFin
ite-Mengen, die für Variablen verwendet werden. Jede solche Menge hat eine konstruktorerhaltendeemb
Einfügung in die obige Menge sowie ein neuestop
Element, und Sie können sie unterscheiden: Dieembd
Funktion sagt Ihnen, ob sich ein Wert im Bild von befindetemb
.Wir können natürlich
Fin
fürZe
und instanziierenSuc
Jetzt kann ich mit einer Schwächungsoperation weniger oder gleich definieren .
Die
wk
Funktion sollte die Elementex
als die größten Elemente von einbetteny
, damit die zusätzlichen Dinge iny
kleiner und damit in de Bruijn-Indexbegriffen lokaler gebunden sind.Und sobald Sie das geklärt haben, erledigt ein bisschen Schädelgraberei den Rest.
Die Funktion höherer Ordnung gibt Ihnen nicht nur einen Begriff, der die Variable darstellt, sondern auch ein überladenes Element, das in jedem Bereich, in dem die Variable sichtbar ist, zur korrekten Darstellung der Variablen wird. Das heißt, die Tatsache, dass ich mir die Mühe mache, die verschiedenen Bereiche nach Typ zu unterscheiden, gibt dem Haskell-Typechecker genügend Informationen, um die Verschiebung zu berechnen, die für die Übersetzung in die de Bruijn-Darstellung erforderlich ist. Warum einen Hund behalten und sich bellen?
quelle
F
Kombinator hinzufügen ?F
verhält sich je nach erstem Argument unterschiedlich: WennA
es sich um ein Atom handeltM
undN
Begriffe undPQ
ein Komposit sind, dannFAMN -> M
undF(PQ)MN -> NPQ
. Dies kann nicht imSK(I)
Kalkül dargestellt werden, sondernK
kann als dargestellt werdenFF
. Ist es möglich, Ihr punktfreies MLTT damit zu verlängern?λ (A : Set) → λ (a : A) → a
Typ(A : Set) → (a : A) → A
übersetztS(S(KS)(KK))(KK)
, der nicht für einen Typ verwendet werden kann, bei dem der Typ des zweiten Arguments vom ersten Argument abhängt.Ich denke, die "Bracket Abstraction" funktioniert unter bestimmten Umständen auch für abhängige Typen. In Abschnitt 5 des folgenden Dokuments finden Sie einige K- und S-Typen:
Unverschämte, aber bedeutungsvolle Zufälle
Abhängige typsichere Syntax und Bewertung
Conor McBride, University of Strathclyde, 2010
Die Umwandlung eines Lambda-Ausdrucks in einen kombinatorischen Ausdruck entspricht in etwa der Umwandlung eines natürlichen Abzugsbeweises in einen Hilbert-Beweis.
quelle