OCaml Modultypen und separate Kompilierung

8

Ich lese OCaml Lead Designer 1994 über Module, Typen und separate Kompilierung (freundlich zu mir von Norman Ramsey in eine andere Frage ). Ich verstehe, dass der Artikel die Ursprünge von OCamls aktuellem Modultyp / Signatursystem diskutiert. Es bietet eine undurchsichtige Interpretation von Typdeklarationen in Signaturen (um eine separate Kompilierung zu ermöglichen) zusammen mit Manifesttypdeklarationen (für Ausdruckskraft) an. Ich versuche, einige Beispiele meiner eigenen zu erstellen, um die Art von Problemen zu demonstrieren, die die OCaml-Modul-Signatur-Notation anzugehen versucht. Ich schrieb den folgenden Code in zwei Dateien:

In der Datei ordering.ml (oder .mli - Ich habe beides versucht) ( Datei A ):

%Vor%

und in Datei useOrdering.ml ( Datei B ):

%Vor%

Die Idee zu erwarten, dass der Compiler sich beschweren wird (beim Kompilieren der zweiten Datei), dass nicht genügend Typinformationen im Modul StringOrdering vorhanden sind, um die StringOrdering.isLess -Anwendung zu prüfen (und damit die with type -Syntax zu motivieren) ). Obwohl Datei A wie erwartet kompiliert, bewirkt Datei B, dass sich die 3.11.2 ocamlc für einen Syntaxfehler beschweren. Ich habe verstanden, dass Signaturen dazu gedacht waren, dass jemand Code basierend auf der Modul-Signatur schreiben konnte, ohne Zugriff auf die Implementierung (die Modulstruktur).

Ich gestehe, dass ich mir über die Syntax nicht sicher bin: module A : B , die ich in dieses ziemlich alte Papier auf der separaten Kompilation aber ich frage mich, ob eine solche oder ähnliche Syntax existiert (ohne Funktoren einzubeziehen), damit jemand Code schreiben kann, der nur auf dem Modultyp basiert, mit die tatsächliche Modulstruktur, die zum Zeitpunkt der Verlinkung zur Verfügung gestellt wird, ähnlich wie man in C / C ++ die Dateien *.h und *.c verwenden kann. Ohne eine solche Fähigkeit scheint es so zu sein, dass Modultypen / Signaturen grundsätzlich dazu dienen, die Interna von Modulen zu verschließen / auszublenden oder explizitere Typprüfungen / Anmerkungen, aber nicht für die separate / unabhängige Kompilierung.

Wenn man sich den OCaml Manual-Abschnitt über Module und separate Compilation anschaut , scheint es dass meine Analogie mit C-Kompilierungseinheiten gebrochen ist, weil das OCaml-Handbuch die OCaml-Kompilierungseinheit als A.ml und A.mli duo definiert, während in C / C ++ die .h -Dateien in die Kompilierungseinheit eines importierenden% eingefügt werden. co_de% Datei.

    
Marcus Junius Brutus 23.03.2012, 17:02
quelle

3 Antworten

5

Der richtige Weg, um so etwas zu tun, ist folgendes:

  1. In ordering.mli schreiben:

    %Vor%
  2. Kompilieren Sie die Datei: ocamlc -c ordering.mli

  3. In einer anderen Datei, beziehen Sie sich auf die kompilierte Signatur:

    %Vor%

    Wenn Sie die Datei kompilieren, erhalten Sie den erwarteten Typfehler (dh string ist nicht kompatibel mit Ordering.StringOrdering.t ). Wenn Sie den Typfehler entfernen möchten, sollten Sie der Definition von with type t = string in StringOrdering die Einschränkung ordering.mli hinzufügen.

Beantworten Sie also Ihre zweite Frage: Ja, im Bytecode-Modus muss der Compiler nur die Schnittstellen kennen, auf die Sie angewiesen sind, und Sie können auswählen, welche Implementierung zum Zeitpunkt der Verbindung verwendet werden soll. Dies gilt standardmäßig nicht für die Kompilierung von systemeigenem Code (aufgrund von Optimierungen zwischen Modulen), Sie können sie jedoch deaktivieren.

    
Thomas 23.03.2012, 18:21
quelle
3

Sie werden wahrscheinlich nur durch die Beziehung zwischen expliziten Modul- und Signaturdefinitionen und der impliziten Definition von Modulen durch .ml / .mli-Dateien verwirrt.

Grundsätzlich, wenn Sie eine Datei a.ml haben und sie in einer anderen Datei verwenden, ist es so, als hätten Sie

geschrieben %Vor%

Wenn Sie auch a.mli haben, dann ist es so, als hätten Sie

geschrieben %Vor%

Beachten Sie, dass dies nur ein Modul mit dem Namen A definiert, nicht ein Modul type . Die Signatur von A kann durch diesen Mechanismus keinen Namen erhalten.

Eine andere Datei, die A verwendet, kann gegen a.mli allein kompiliert werden, ohne überhaupt a.ml zur Verfügung zu stellen. Sie möchten jedoch sicherstellen, dass alle Typinformationen bei Bedarf transparent gemacht werden. Angenommen, Sie definieren eine Map über Ganzzahlen:

%Vor%

Hier wird key transparent gemacht, weil jeder Client-Code (des Moduls IntMap , das diese Signatur beschreibt) wissen muss, was es ist, etwas zur Karte hinzufügen zu können. Der map -Typ selbst kann (und sollte) jedoch abstrakt gehalten werden, da ein Client sich nicht mit seinen Implementierungsdetails anlegen sollte.

Die Beziehung zu C-Header-Dateien besteht darin, dass grundsätzlich nur transparente Typen zulassen. In Ocaml haben Sie die Wahl.

    
Andreas Rossberg 23.03.2012 20:47
quelle
3

module StringOrdering : ORDERING ist eine Moduldeklaration. Sie können dies in einer Signatur verwenden, um zu sagen, dass die Signatur ein Modulfeld namens StringOrdering und die Signatur ORDERING enthält. Es macht keinen Sinn in einem Modul.

Sie müssen irgendwo ein Modul definieren, das die benötigten Operationen implementiert. Die Moduldefinition kann etwas wie

sein %Vor%

Wenn Sie die Definition des Typs t ausblenden möchten, müssen Sie ein anderes Modul erstellen, in dem die Definition abstrakt ist. Die Operation zum Erstellen eines neuen Moduls aus einem alten Modul wird als Versiegelung bezeichnet und durch den Operator : ausgedrückt.

%Vor%

Dann ist StringOrderingImplementation.isLess "a" "b" gut typisiert, während StringOrderingAbstract.isLess "a" "b" nicht typisiert werden kann, da StringOrderingAbstract.t ein abstrakter Typ ist, der nicht mit string oder einem anderen bereits bestehenden Typ kompatibel ist. In der Tat ist es unmöglich, einen Wert vom Typ StringOrderingAbstract.t zu erstellen, da das Modul keinen Konstruktor enthält.

Wenn Sie eine Übersetzungseinheit foo.ml haben, ist dies ein Modul Foo , und die Signatur dieses Moduls wird von der Schnittstellendatei foo.mli vergeben. Das heißt, die Dateien foo.ml und foo.mli entsprechen der Moduldefinition

%Vor%

Beim Kompilieren eines Moduls, das Foo verwendet, sieht der Compiler nur foo.mli (bzw. das Ergebnis seiner Kompilierung: foo.cmi ), nicht foo.ml ¹. So passen Schnittstellen und separate Kompilierung zusammen. C benötigt #include <foo.h> , weil es keine Form von Namespace hat; In OCaml verweist Foo.bar automatisch auf ein bar , das in der Kompilierungseinheit foo definiert ist, wenn kein anderes Modul namens Foo im Bereich vorhanden ist.

¹ Tatsächlich untersucht der Compiler für den nativen Code die Implementierung von Foo , um Optimierungen durchzuführen (Inlining). Der Typ-Checker sieht nie etwas anderes als das, was in der Schnittstelle ist.

    
Gilles 25.03.2012 23:55
quelle

Tags und Links