Ich habe sehr lange über diese Frage nachgedacht, konnte aber die Antwort bei Google und eine ähnliche Frage bei Stackoverflow wirklich nicht finden. Wenn es ein Duplikat gibt, tut mir das leid.
Viele Leute scheinen zu sagen, dass das Schreiben von Compilern und anderen Sprachwerkzeugen in funktionalen Sprachen wie OCaml und Haskell viel effizienter und einfacher ist als das Schreiben in imperativen Sprachen.
Ist das wahr? Und wenn ja - warum ist es so effizient und einfach, sie in funktionalen Sprachen anstatt in einer imperativen Sprache wie C zu schreiben? Auch - ist ein Sprachwerkzeug in einer funktionalen Sprache nicht langsamer als in einer einfachen Sprache wie C?
Antworten:
Oft arbeitet ein Compiler viel mit Bäumen. Der Quellcode wird in einen Syntaxbaum analysiert. Dieser Baum kann dann in einen anderen Baum mit Typanmerkungen umgewandelt werden, um eine Typprüfung durchzuführen. Jetzt können Sie diesen Baum in einen Baum konvertieren, der nur Elemente der Kernsprache enthält (syntaktische zuckerähnliche Notationen in eine nicht empfohlene Form konvertieren). Jetzt können Sie verschiedene Optimierungen durchführen, bei denen es sich im Grunde um Transformationen des Baums handelt. Danach würden Sie wahrscheinlich einen Baum in einer normalen Form erstellen und dann über diesen Baum iterieren, um den Zielcode (Assemblycode) zu erstellen.
Die funktionale Sprache verfügt über Funktionen wie Pattern Matching und eine gute Unterstützung für eine effiziente Rekursion, die das Arbeiten mit Bäumen vereinfachen. Deshalb gelten sie im Allgemeinen als gute Sprachen zum Schreiben von Compilern.
quelle
Viele Compiler-Aufgaben sind Mustervergleiche in Baumstrukturen.
Sowohl OCaml als auch Haskell verfügen über leistungsstarke und präzise Mustervergleichsfunktionen.
Es ist schwieriger, den imperativen Sprachen einen Mustervergleich hinzuzufügen, da jeder Wert, der ausgewertet oder extrahiert wird, um das Muster abzugleichen, nebenwirkungsfrei sein muss.
quelle
Ein wichtiger Faktor ist, dass ein großer Teil jedes Compiler-Projekts darin besteht, dass Sie den Compiler selbst hosten und "Ihr eigenes Hundefutter essen" können. Aus diesem Grund bieten Sprachen wie OCaml, in denen sie für die Sprachforschung entwickelt wurden, in der Regel hervorragende Funktionen für Probleme vom Typ Compiler.
In meinem letzten compilerähnlichen Job haben wir OCaml aus genau diesem Grund verwendet, während wir C-Code manipulierten. Es war einfach das beste Werkzeug für diese Aufgabe. Wenn die Leute von INRIA OCaml mit unterschiedlichen Prioritäten gebaut hätten, wäre es vielleicht nicht so gut gewesen.
Das heißt, funktionale Sprachen sind das beste Werkzeug zur Lösung eines Problems, daher folgt logischerweise, dass sie das beste Werkzeug zur Lösung dieses speziellen Problems sind. QED.
/ me: kriecht etwas weniger freudig zu meinen Java-Aufgaben zurück ...
quelle
Grundsätzlich ist ein Compiler eine Transformation von einem Codesatz zu einem anderen - von Quelle zu IR, von IR zu optimiertem IR, von IR zu Assembly usw. Genau dafür sind funktionale Sprachen konzipiert - eine reine Funktion ist nur eine Transformation von einer Sache zur anderen. Imperative Funktionen haben diese Qualität nicht. Obwohl Sie diese Art von Code in einer zwingenden Sprache schreiben können, sind funktionale Sprachen darauf spezialisiert.
quelle
Siehe auch
F # Designmuster
FP gruppiert Dinge 'nach Operation', während OO Dinge 'nach Typ' gruppiert und 'nach Operation' für einen Compiler / Interpreter natürlicher ist.
quelle
Eine Möglichkeit besteht darin, dass ein Compiler dazu neigt, sehr sorgfältig mit einer ganzen Reihe von Eckfällen umzugehen. Die Richtigkeit des Codes wird häufig durch die Verwendung von Entwurfsmustern erleichtert, die die Implementierung so strukturieren, dass sie den implementierten Regeln entsprechen. Oft ist dies eher ein deklaratives (Mustervergleich, "wo") als ein imperatives (Sequenzierung, "wann") Design und daher einfacher in einer deklarativen Sprache zu implementieren (und die meisten von ihnen sind funktional).
quelle
Scheint, als hätten alle einen anderen wichtigen Grund verpasst. Es ist ziemlich einfach, eine eingebettete domänenspezifische Sprache (EDSL) für Parser zu schreiben, die (E) BNF im normalen Code sehr ähnlich sehen. Parser-Kombinatoren wie Parsec lassen sich mit Funktionen höherer Ordnung und Funktionszusammensetzung recht einfach in funktionalen Sprachen schreiben. Nicht nur einfacher, sondern auch sehr elegant.
Grundsätzlich stellen Sie nur den einfachsten generic - Parser als nur Funktionen und Sie haben spezielle Operationen ( in der Regel Funktionen höhere Ordnung) , die können Sie komponieren , diese primitiven Parser in kompliziertem, spezifischen Parser für die Grammatik.
Dies ist natürlich nicht die einzige Möglichkeit, Parer-Frameworks zu erstellen.
quelle