Neues C++-Backend für den OCaml-Compiler
(github.com/ocaml)- Für den OCaml-Compiler wurde ein neues Backend mit Unterstützung für die Erzeugung von C++-Code vorgeschlagen, das die Grenzen des bisherigen C-basierten Backends ergänzt
- Der umgewandelte Code ist in einem rein funktionalen Stil geschrieben und implementiert ohne veränderbaren Zustand oder Nutzung der Standardbibliothek Teile des
List-Moduls neu - Für die Ausführung wird ein C++-Compiler (
g++) benötigt; unterstützt werden Optionen zum Aufheben der Template-Tiefenbegrenzung und zur Übergabe von Argumenten - Die Performance unterscheidet sich je nach Compiler; mit einem verbesserten Sieb-Algorithmus auf Basis einer Prioritätswarteschlange werden Geschwindigkeit und Speichereffizienz verbessert
- Die Community bewertet dies als Experiment zur Verbindung funktionaler Sprachen mit Template-Metaprogrammierung; auch eine mögliche Erweiterung auf Rust wird erwähnt
Vorschlag zur Ergänzung eines C++-Backends
- Ein Patch zur Ergänzung eines C++-Backends für den OCaml-Compiler (
ocamlc) wurde vorgeschlagen- Eine verbesserte Form des nichtinkrementellen C-Backends, das bereits in Runtime und FFI verwendet wird
- Mit dem Befehl
ocamlc -incr-c primes.mllässt sich OCaml-Code in C++ umwandeln
- Der erzeugte C++-Code ist in einem rein funktionalen Stil geschrieben und unterstützt keinen veränderbaren Zustand
- Dadurch ist die Nutzung der Standardbibliothek nicht möglich; im Beispiel werden Teile des
List-Moduls rein funktional neu implementiert - Die Ausgabe wird als verschachtelte Struktur in der Form
Cons<hd, tl>dargestellt; zur Vermeidung eines Konflikts mit dem::-Operator in C++ wird eine separate Struktur verwendet
- Dadurch ist die Nutzung der Standardbibliothek nicht möglich; im Beispiel werden Teile des
- Für die Ausführung wird ein C++-Compiler (
g++) benötigt, und mit der Option-Dlimit=100können Argumente übergeben werden- Das Ausführungsergebnis wird im Format einer Compiler-Fehlermeldung ausgegeben
- Bei großen Berechnungen kann mit der Option
-ftemplate-depth=999999die Begrenzung der Template-Tiefe aufgehoben werden
- Die Performance unterscheidet sich je nach Compiler
g++benötigt für die Berechnung von Primzahlen bis 10000 etwa 30 Sekunden und 11 GiB Speicherclang++gibt innerhalb einer Sekunde eine Warnung aus und endet dann mit einem Segmentation Fault- Mit Anwendung von O’Neills Sieb-Algorithmus auf Basis einer Prioritätswarteschlange verbessert sich das auf 8 Sekunden und 3,1 GiB
- Als mögliche künftige Erweiterung wird Unterstützung für Rust erwähnt
- Es wird angemerkt, dass die Ausführung von OCaml-Programmen möglich sein könnte, sobald Rust eine partielle
impl specializationvollständig unterstützt
- Es wird angemerkt, dass die Ausführung von OCaml-Programmen möglich sein könnte, sobald Rust eine partielle
Reaktionen und Diskussionen in der Community
-
Funktionstests und Feedback
redianthusfragte, ob nichtuniform rekursive Datentypen unterstützt werdenstedolanbehob einen Fehler durch die nicht implementierte%predint-Funktion und bestätigte, dass der betreffende Typ korrekt funktioniert
-
Humor und Reaktionen
avsmmachte den Witz: „Wir brauchten C--, aber es ist C++; einigen wir uns auf C#“stedolanantwortete, er werde „nächstes Jahr die komplexen Zahlen ℂ ausprobieren“- Zahlreiche Emoji-Reaktionen wie 😂, ❤️ und 🚀 zeigen die positive Resonanz in der Community
-
Technische Vorschläge
AdelKSschlug eine Alternative vor, bei derconstexpr-Auswertung statt Templates verwendet wird- Er teilte Beispielcode, der Primzahlen zur Compile-Zeit berechnet und direkt in das Binärprogramm einbettet
LoganDarkantwortete scherzhaft, „das sei nur zum reinen Spaß“, und erklärte so humorvoll den Einsatz von Templates
-
Weitere Diskussionen
redianthusbemerkte, dass „C++ jetzt endlich eine echte funktionale Sprache geworden ist“- Dabei wurde betont, dass sich die rein funktionalen Datenstrukturen von OCaml in C++ umsetzen lassen
dzmitry-lahodaerwähnte, dass es auch für Rust bereits ein Projekt gibt, das OCaml ausführen kann (contextgeneric/cgp)
Performance- und Ausführungsbeispiele
- Grundbeispiel: Programm zur Berechnung von Primzahlen
ocamlc -incr-c primes.ml→primes.cppwird erzeugt- Bei Ausführung von
g++ -Dlimit=100 primes.cppwird eine Liste von Primzahlen ausgegeben
-
Konfiguration für hohe Leistung
g++ -ftemplate-depth=999999 -Dlimit=10000 primes.cpp- Etwa 30 Sekunden, 11 GiB Speicherverbrauch
-
Bei Verwendung des verbesserten Algorithmus
- Verbesserung auf 8 Sekunden und 3,1 GiB
Fazit
- Dieser PR ist ein Experiment mit einem neuen Backend, das OCaml in C++ umwandelt, und zeigt die Möglichkeit einer Verbindung von funktionalen Sprachen und Template-Metaprogrammierung
- Die Community nimmt dies als Kombination aus technischem Humor und kreativem Experiment auf und reagiert lebhaft
- Auch die Möglichkeit einer Erweiterung auf andere Sprachen wie Rust wird aufgezeigt
1 Kommentare
Hacker-News-Kommentare
Wirklich großartiger Inhalt. Ich möchte einen Tipp geben, wenn man C++-Code schreibt, der lange läuft
Seltsamerweise haben C++-Interpreter überhaupt keine Tail-Call-Optimization
Deshalb implementiert der meiste idiomatische C++-Code Funktionen wie
reverse,map,rangeundfilterselbst, damit einem nicht der Stack um die Ohren fliegtWenn man es auf diese Weise implementiert, ist es für die Wartenden deutlich angenehmer. Es ist besser, einen portablen Ansatz zu verwenden, statt sich auf Kommandozeilen-Flags zu verlassen
Ich musste lachen, als ich den Satz las: „Mit solchen fortgeschrittenen Datenstrukturen kann g++ Primzahlen bis 10000 in nur 8 Sekunden berechnen und dabei lediglich 3.1GiB Speicher verwenden“
Endlich kann ich jetzt auch auf meinem Laptop Primzahlen berechnen
Mit dem Teil „Dieser Code wird in idiomatisches und gut lesbares C++ übersetzt“ konnte ich mich wirklich identifizieren
Als jemand, der C++ mag, finde ich, dass das wirklich gut lesbarer C++-Code ist
typedef I<((I<((n::val (p::val))>::val) != (I<0>::val))> res;ist wirklich magisches Template-HexenwerkIch habe zum ersten Mal gesehen, dass in C++ ein Bedingungsausdruck innerhalb einer Typdefinition steckt
Später habe ich gemerkt, dass das kein eigentlicher Code war, sondern Teil der Template-Auswertungslogik
Das heißt, ein Teil der Compiler-Logik einer High-Level-Sprache wurde gewissermaßen an die Template-Engine ausgelagert
So ein Ansatz könnte effizienter sein, als mehr Zeit in den Parser zu stecken
Deshalb überlege ich jetzt, C++ als Lowering-Ziel für das elevate Compiler-Framework zu verwenden, an dem ich arbeite
Als ich den Satz „C++ is a purely functional language“ sah, dachte ich zuerst, es sei ein Tippfehler, und zog die Augenbrauen hoch
Als ich dann merkte, dass es kein Tippfehler war, fand ich es noch interessanter. Der Rest des Inhalts war ebenfalls großartig
Dank dieses Beitrags war mein Tag gleich schöner. Danke
Stephen Dolan enttäuscht wirklich nie. Jedes Mal überrascht er aufs Neue
Beim Teil „C++ ist eine rein funktionale Sprache und unterstützt keinen veränderlichen Zustand. Um ein C++-Programm auszuführen, braucht man einen C++-Interpreter“
dachte ich im ersten Moment, es sei ein Aprilscherz. Dabei ist der April längst vorbei