Ich arbeite an einem Compiler für eine verkettete Sprache und möchte Unterstützung für Typinferenz hinzufügen. Ich verstehe Hindley-Milner, aber ich habe die Typentheorie im Laufe der Zeit gelernt, daher bin ich mir nicht sicher, wie ich sie anpassen soll. Ist das folgende System solide und eindeutig ableitbar?
Ein Begriff ist ein Literal, eine Zusammensetzung von Begriffen, ein Zitat eines Begriffs oder ein Primitiv.
Alle Begriffe bezeichnen Funktionen. Für zwei Funktionen und , , das heißt, die Nebeneinanderstellung bezeichnet die umgekehrte Zusammensetzung. Literale bezeichnen niladische Funktionen.
Die Begriffe außer Komposition haben grundlegende Typregeln:
Insbesondere fehlen Anwendungsregeln, da es an konkatenativen Sprachen mangelt.
Ein Typ ist entweder ein Literal, eine Typvariable oder eine Funktion von Stapel zu Stapel, wobei ein Stapel als rechtsverschachteltes Tupel definiert ist. Alle Funktionen sind implizit polymorph in Bezug auf den "Rest des Stapels".
Dies ist das erste, was verdächtig erscheint, aber ich weiß nicht genau, was daran falsch ist.
Um die Lesbarkeit zu verbessern und Klammern zu reduzieren, gehe ich davon aus, dass in Typschemata. Ich werde auch einen Großbuchstaben für eine Variable verwenden, die einen Stapel statt eines einzelnen Werts bezeichnet.
Es gibt sechs Grundelemente. Die ersten fünf sind ziemlich harmlos. dup
Nimmt den höchsten Wert und erstellt zwei Kopien davon. swap
Ändert die Reihenfolge der beiden obersten Werte. pop
verwirft den obersten Wert. quote
Nimmt einen Wert und erzeugt ein Zitat (eine Funktion), das ihn zurückgibt. apply
Wendet ein Zitat auf den Stapel an.
Der letzte Kombinator compose
, sollte zwei Zitate nehmen und die Art ihrer Verkettung zurück, das heißt, . In der statisch typisierten VerkettungsspracheCatist der Typ vonsehr einfach.compose
Dieser Typ ist jedoch zu restriktiv: Er erfordert, dass die Produktion der ersten Funktion genau mit dem Verbrauch der zweiten Funktion übereinstimmt . In Wirklichkeit muss man verschiedene Typen annehmen und sie dann vereinheitlichen. Aber wie würden Sie diesen Typ schreiben?
Wenn Sie lassen einen bezeichnen Unterschied von zwei Typen, dann ich denke , Sie die Art der schreiben kann compose
richtig.
Dies ist immer noch relativ einfach: compose
nimmt eine Funktion und eine f 2 : D → E . Sein Ergebnis verbraucht B oben auf dem Verbrauch von f 2 nicht erzeugt f 1 und erzeugt D oben auf die Herstellung von f 1 nicht verbraucht durch f 2 . Dies gibt die Regel für die gewöhnliche Zusammensetzung.
Ich weiß jedoch nicht, dass dieses hypothetische tatsächlich irgendetwas entspricht, und ich habe es lange genug im Kreis herumgejagt , sodass ich glaube, dass ich falsch abgebogen bin. Könnte es ein einfacher Unterschied von Tupeln sein?
Gibt es etwas Schreckliches daran, das ich nicht sehe, oder bin ich auf dem richtigen Weg? (Ich habe wahrscheinlich einige dieser Dinge falsch quantifiziert und würde auch Korrekturen in diesem Bereich begrüßen.)
compose
twice
dup compose apply
[1 +] twice
[pop] twice
compose
without some circular definition.Antworten:
The following rank-2 type
Griechische Buchstaben werden nur aus Gründen der Übersichtlichkeit für die übrigen Stapelvariablen verwendet.
Es drückt die Einschränkungen aus, dass der Ausgabestapel des ersten Elements im Stapel mit dem Eingabestapel des zweiten Elements identisch sein muss. Variable entsprechend instanziierenB Denn mit den beiden eigentlichen Argumenten wird erreicht, dass die Einschränkungen ordnungsgemäß funktionieren, anstatt eine neue Operation zu definieren, wie Sie in der Frage vorschlagen.
Type checking rank-2 types is undecidable in general, I believe, though some work has been done that gives good results in practice (for Haskell):
The type rule for composition is simply:
To get the type system to work in general, you need the following specialisation rule:
quelle
dup +
should have type+
has typedup +
, as that does not use compose, as you defined it above.[dup] [+] compose
. But I read