1 Punkte von GN⁺ 27 일 전 | 1 Kommentare | Auf WhatsApp teilen
  • 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.ml lä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
  • Für die Ausführung wird ein C++-Compiler (g++) benötigt, und mit der Option -Dlimit=100 können Argumente übergeben werden
    • Das Ausführungsergebnis wird im Format einer Compiler-Fehlermeldung ausgegeben
    • Bei großen Berechnungen kann mit der Option -ftemplate-depth=999999 die 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 Speicher
    • clang++ 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 specialization vollständig unterstützt

Reaktionen und Diskussionen in der Community

  • Funktionstests und Feedback

    • redianthus fragte, ob nichtuniform rekursive Datentypen unterstützt werden
    • stedolan behob einen Fehler durch die nicht implementierte %predint-Funktion und bestätigte, dass der betreffende Typ korrekt funktioniert
  • Humor und Reaktionen

    • avsm machte den Witz: „Wir brauchten C--, aber es ist C++; einigen wir uns auf C#“
    • stedolan antwortete, er werde „nächstes Jahr die komplexen Zahlen ℂ ausprobieren“
    • Zahlreiche Emoji-Reaktionen wie 😂, ❤️ und 🚀 zeigen die positive Resonanz in der Community
  • Technische Vorschläge

    • AdelKS schlug eine Alternative vor, bei der constexpr-Auswertung statt Templates verwendet wird
      • Er teilte Beispielcode, der Primzahlen zur Compile-Zeit berechnet und direkt in das Binärprogramm einbettet
    • LoganDark antwortete scherzhaft, „das sei nur zum reinen Spaß“, und erklärte so humorvoll den Einsatz von Templates
  • Weitere Diskussionen

    • redianthus bemerkte, 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-lahoda erwä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.mlprimes.cpp wird erzeugt
    • Bei Ausführung von g++ -Dlimit=100 primes.cpp wird 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

 
GN⁺ 27 일 전
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, range und filter selbst, damit einem nicht der Stack um die Ohren fliegt
    Wenn 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

    • Im Großen und Ganzen stimme ich zu, aber so etwas wie typedef I<((I<((n::val (p::val))>::val) != (I<0>::val))> res; ist wirklich magisches Template-Hexenwerk
      Ich 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