Ich arbeite an einem kleinen Lambda-Kalkül-Compiler, der über ein funktionierendes Inferenzsystem vom Typ Hindley-Milner verfügt und jetzt auch rekursive Let's (nicht im verknüpften Code) unterstützt. Ich verstehe, dass dies ausreichen sollte, um Turing vollständig zu machen .
Das Problem ist jetzt, dass ich keine Ahnung habe, wie ich es zu Unterstützungslisten machen soll oder ob es sie bereits unterstützt, und ich muss nur einen Weg finden, sie zu codieren. Ich möchte sie definieren können, ohne dem Typsystem neue Regeln hinzufügen zu müssen.
Der einfachste Weg, wie ich mir eine Liste vorstellen kann, x
ist etwas, das entweder null
(oder die leere Liste) ist, oder ein Paar, das sowohl eine x
als auch eine Liste von enthält x
. Aber um dies zu tun, muss ich in der Lage sein, Paare und / oder zu definieren, von denen ich glaube, dass sie das Produkt und die Summentypen sind.
Scheint, dass ich Paare folgendermaßen definieren kann:
pair = λabf.fab
first = λp.p(λab.a)
second = λp.p(λab.b)
Da pair
der Typ a -> (b -> ((a -> (b -> x)) -> x))
nach dem Übergeben von beispielsweise a int
und a string
etwas mit Typ ergeben würde (int -> (string -> x)) -> x
, wäre dies die Darstellung eines Paares von int
und string
. Was mich hier stört, ist, dass wenn das ein Paar darstellt, warum das nicht logisch äquivalent ist oder den Satz impliziert int and string
? Dies entspricht jedoch (((int and string) -> x) -> x)
, als ob ich nur Produkttypen als Parameter für Funktionen haben könnte. Diese Antwortscheinen dieses Problem anzusprechen, aber ich habe keine Ahnung, was die von ihm verwendeten Symbole bedeuten. Wenn dies einen Produkttyp nicht wirklich codiert, kann ich dann etwas mit Produkttypen tun, die ich mit meiner obigen Definition von Paaren nicht tun konnte (wenn ich bedenke, dass ich auf die gleiche Weise auch n-Tupel definieren kann)? Wenn nicht, würde dies nicht der Tatsache widersprechen, dass Sie die AFAIK-Konjunktion nicht nur implizit ausdrücken können?
Wie wäre es auch mit dem Summentyp? Kann ich es irgendwie nur mit dem Funktionstyp codieren? Wenn ja, würde dies ausreichen, um Listen zu definieren? Oder gibt es eine andere Möglichkeit, Listen zu definieren, ohne mein Typensystem erweitern zu müssen? Und wenn nicht, welche Änderungen müsste ich vornehmen, um es so einfach wie möglich zu halten?
Bitte denken Sie daran, dass ich ein Computerprogrammierer bin, aber kein Informatiker oder Mathematiker und ziemlich schlecht darin, Mathematiknotation zu lesen.
Bearbeiten: Ich bin nicht sicher, wie der technische Name meiner bisherigen Implementierung lautet, aber alles, was ich habe, ist im Grunde der Code, den ich oben verlinkt habe. Hierbei handelt es sich um einen Algorithmus zur Generierung von Einschränkungen, der die Regeln für Anwendungen, Abstraktionen und Variablen verwendet vom Hinley-Milner-Algorithmus und dann einem Vereinigungsalgorithmus, der den Haupttyp erhält. Beispielsweise gibt der Ausdruck \a.a
den Typ aus a -> a
, und der Ausdruck \a.(a a)
löst einen aufgetretenen Überprüfungsfehler aus. Darüber hinaus gibt es nicht genau eine let
Regel, sondern eine Funktion, die den gleichen Effekt zu haben scheint, mit der Sie rekursive globale Funktionen wie diesen Pseudocode definieren können:
GetTypeOfGlobalFunction(term, globalScope, nameOfFunction)
{
// Here 'globalScope' contains a list of name-value pair where every value is of class 'ClosedType',
// meaning their type will be cloned before unified in the unification algorithm so that they can be used polymorphically
tempType = new TypeVariable() // Assign a dummy type to `tempType`, say, type 'x'.
// The next line creates an scope with everything in 'globalScope' plus the 'nameOfFunction = tempType' name-value pair
tempScope = new Scope(globalScope, nameOfFunction, tempType)
type = TypeOfTerm(term, tempScope) // Calculate the type of the term
Unify(tempType, type)
return type
// After returning, the code outside will create a 'ClosedType' using the returned type and add it to the global scope.
}
Der Code erhält grundsätzlich den Typ des Begriffs wie gewohnt, fügt jedoch vor dem Vereinheitlichen den Namen der Funktion, die mit einem Dummy-Typ definiert wird, in den Typbereich ein, damit er rekursiv aus sich heraus verwendet werden kann.
Bearbeiten 2: Ich habe gerade festgestellt, dass ich auch rekursive Typen benötigen würde, die ich nicht habe, um eine Liste wie gewünscht zu definieren.
let func = \x -> (func x)
) beschränken, erhalten Sie, was ich habe.