Eine klassische Programmierübung besteht darin, einen Lisp / Scheme-Interpreter in Lisp / Scheme zu schreiben. Die Leistung der vollständigen Sprache kann genutzt werden, um einen Interpreter für eine Teilmenge der Sprache zu erstellen.
Gibt es eine ähnliche Übung für Haskell? Ich möchte eine Teilmenge von Haskell mit Haskell als Engine implementieren. Natürlich ist dies möglich, aber gibt es Online-Ressourcen, die Sie sich ansehen können?
Hier ist die Hintergrundgeschichte.
Ich untersuche die Idee, Haskell als Sprache zu verwenden, um einige der Konzepte in einem von mir unterrichteten Kurs für diskrete Strukturen zu untersuchen . Für dieses Semester habe ich mich für Miranda entschieden , eine kleinere Sprache, die Haskell inspiriert hat. Miranda macht ungefähr 90% von dem, was ich möchte, aber Haskell macht ungefähr 2000%. :) :)
Meine Idee ist es also, eine Sprache zu erstellen, die genau die Funktionen von Haskell enthält, die ich möchte, und alles andere nicht zulässt. Während die Schüler Fortschritte machen, kann ich verschiedene Funktionen selektiv "einschalten", sobald sie die Grundlagen beherrschen.
Pädagogische "Sprachniveaus" wurden erfolgreich verwendet, um Java und Schema zu unterrichten . Indem Sie ihre Möglichkeiten einschränken, können Sie verhindern, dass sie sich in den Fuß schießen, während sie noch die Syntax und Konzepte beherrschen, die Sie vermitteln möchten. Und Sie können bessere Fehlermeldungen anbieten.
quelle
Antworten:
Ich liebe dein Ziel, aber es ist ein großer Job. Ein paar Tipps:
Ich habe an GHC gearbeitet, und Sie wollen keinen Teil der Quellen. Hugs ist eine viel einfachere und sauberere Implementierung, aber leider in C.
Es ist ein kleines Puzzleteil, aber Mark Jones hat ein wunderschönes Papier namens Typing Haskell in Haskell geschrieben, das ein guter Ausgangspunkt für Ihr Frontend wäre.
Viel Glück! Die Ermittlung der Sprachniveaus für Haskell mit Belegen aus dem Klassenzimmer wäre für die Community von großem Nutzen und definitiv ein publizierbares Ergebnis!
quelle
Notes
Informationen sind hilfreich, um Details auf niedriger Ebene zu verstehen, und das Kapitel über GHC in Die Architektur von Open Source-Anwendungen bietet einen hervorragenden Überblick auf hoher Ebene.Es gibt einen vollständigen Haskell-Parser: http://hackage.haskell.org/package/haskell-src-exts
Sobald Sie es analysiert haben, ist es einfach, bestimmte Dinge zu entfernen oder zu verbieten. Ich habe dies für tryhaskell.org getan, um Importanweisungen zu verbieten, Definitionen der obersten Ebene zu unterstützen usw.
Analysieren Sie einfach das Modul:
Dann haben Sie einen AST für ein Modul:
Der Decl-Typ ist umfangreich: http://hackage.haskell.org/packages/archive/haskell-src-exts/1.9.0/doc/html/Language-Haskell-Exts-Syntax.html#t%3ADecl
Alles, was Sie tun müssen, ist eine weiße Liste zu definieren - welche Deklarationen, Importe, Symbole und Syntax verfügbar sind, dann den AST zu durchlaufen und einen "Analysefehler" auf alles zu werfen, von dem Sie nicht möchten, dass sie es noch wissen. Sie können den SrcLoc-Wert verwenden, der an jeden Knoten im AST angehängt ist:
Haskell muss nicht erneut implementiert werden. Wenn Sie benutzerfreundlichere Kompilierungsfehler bereitstellen möchten, analysieren Sie einfach den Code, filtern Sie ihn, senden Sie ihn an den Compiler und analysieren Sie die Compilerausgabe. Wenn es sich um ein "nicht erwarteter Typ a gegen abgeleitet
a -> b
" handelt, wissen Sie, dass es wahrscheinlich zu wenige Argumente für eine Funktion gibt.Wenn Sie nicht wirklich wirklich Zeit damit verbringen möchten, Haskell von Grund auf neu zu implementieren oder sich mit den Interna von Hugs oder einer dummen Implementierung herumzuschlagen, sollten Sie einfach filtern, was an GHC übergeben wird. Auf diese Weise ist der Übergang transparent, wenn Ihre Schüler ihre Codebasis verwenden und zum nächsten Schritt übergehen und echten, vollwertigen Haskell-Code schreiben möchten.
quelle
Möchten Sie Ihren Dolmetscher von Grund auf neu erstellen? Beginnen Sie mit der Implementierung einer einfacheren Funktionssprache wie dem Lambda-Kalkül oder einer Lisp-Variante. Für letztere gibt es ein ziemlich schönes Wikibook namens Write yourself a Scheme in 48 Stunden , das eine coole und pragmatische Einführung in Parsing- und Interpretationstechniken bietet.
Das manuelle Interpretieren von Haskell wird viel komplexer, da Sie sich mit hochkomplexen Funktionen wie Typklassen, einem äußerst leistungsfähigen Typensystem (Typinferenz!) Und einer verzögerten Bewertung (Reduktionstechniken) befassen müssen.
Sie sollten also eine kleine Teilmenge von Haskell definieren, mit der Sie arbeiten möchten, und dann möglicherweise das Schema-Beispiel Schritt für Schritt erweitern.
Zusatz:
Beachten Sie, dass Sie in Haskell vollen Zugriff auf die Interpreter-API haben (zumindest unter GHC), einschließlich Parser, Compiler und natürlich Interpreter.
Das zu verwendende Paket ist ein Hinweis (Language.Haskell. *) . Ich habe leider weder Online-Tutorials dazu gefunden noch selbst ausprobiert, aber es sieht vielversprechend aus.
quelle
Ich schlage eine einfachere (wie bei weniger Arbeit) Lösung für dieses Problem vor. Anstatt eine Haskell-Implementierung zu erstellen, in der Sie Features deaktivieren können, schließen Sie einen Haskell-Compiler mit einem Programm ein, das zunächst überprüft, ob der Code keine nicht zugelassenen Features verwendet, und dann den vorgefertigten Compiler zum Kompilieren verwendet.
Das wäre ähnlich wie HLint (und auch das Gegenteil davon):
quelle
Baskell ist eine Lehrimplementierung, http://hackage.haskell.org/package/baskell
Sie können zunächst nur das zu implementierende Typsystem auswählen. Das ist ungefähr so kompliziert wie ein Dolmetscher für Scheme, http://hackage.haskell.org/package/thih
quelle
Die EHC-Compilerserie ist wahrscheinlich die beste Wahl: Sie wird aktiv entwickelt und scheint genau das zu sein, was Sie wollen - eine Reihe kleiner Lambda-Kalkül-Compiler / Interpreter, die in Haskell '98 gipfeln.
Sie können sich aber auch die verschiedenen Sprachen ansehen, die in Pierces Typen und Programmiersprachen entwickelt wurden , oder den Helium-Interpreter (ein verkrüppelter Haskell für Studenten http://en.wikipedia.org/wiki/Helium_(Haskell) ).
quelle
Wenn Sie nach einer Teilmenge von Haskell suchen, die einfach zu implementieren ist, können Sie auf Typklassen und Typprüfung verzichten. Ohne Typklassen benötigen Sie keine Typinferenz, um den Haskell-Code auszuwerten.
Ich habe einen selbstkompilierenden Haskell-Subset-Compiler für eine Code Golf-Herausforderung geschrieben. Es verwendet Haskell-Teilmengencode bei der Eingabe und erzeugt C-Code bei der Ausgabe. Es tut mir leid, dass keine besser lesbare Version verfügbar ist. Ich habe verschachtelte Definitionen von Hand aufgehoben, um sie selbst zu kompilieren.
Für einen Studenten, der einen Dolmetscher für eine Teilmenge von Haskell implementieren möchte, würde ich empfehlen, mit den folgenden Funktionen zu beginnen:
Faule Bewertung. Wenn sich der Dolmetscher in Haskell befindet, müssen Sie möglicherweise nichts dafür tun.
Funktionsdefinitionen mit musterangepassten Argumenten und Schutzvorrichtungen. Sorgen Sie sich nur um Variablen, Nachteile, Null und
_
Muster.Einfache Ausdruckssyntax:
Ganzzahlige Literale
Zeichenliterale
[]
(Null)Funktionsanwendung (links assoziativ)
Infix
:
(Nachteile, rechter Assoziativ)Klammer
Variablennamen
Funktionsnamen
Schreiben Sie konkreter einen Interpreter, der dies ausführen kann:
Die Typprüfung ist ein entscheidendes Merkmal von Haskell. Es ist jedoch sehr schwierig, von nichts zu einem Haskell-Compiler mit Typprüfung überzugehen. Wenn Sie zunächst einen Interpreter für das oben Gesagte schreiben, sollte das Hinzufügen einer Typprüfung weniger entmutigend sein.
quelle
Sie könnten sich Happy (einen Yacc-ähnlichen Parser in Haskell) ansehen, der einen Haskell-Parser hat.
quelle
Dies könnte eine gute Idee sein - erstellen Sie eine winzige Version von NetLogo in Haskell. Hier ist der kleine Dolmetscher.
quelle
Sehen Sie, ob Helium eine bessere Basis als Standard-Haskell darstellt.
quelle
Uhc / Ehc ist eine Reihe von Compilern, die verschiedene Haskell-Funktionen aktivieren / deaktivieren. http://www.cs.uu.nl/wiki/Ehc/WebHome#What_is_UHC_And_EHC
quelle
Mir wurde gesagt, dass Idris einen ziemlich kompakten Parser hat, nicht sicher, ob er wirklich für Änderungen geeignet ist, aber er ist in Haskell geschrieben.
quelle
Der Programmiersprachen-Zoo von Andrej Bauer hat eine kleine Implementierung einer rein funktionalen Programmiersprache mit dem etwas frechen Namen "Minihaskell". Es sind ungefähr 700 Linien OCaml, also sehr leicht zu verdauen.
Die Site enthält auch Spielzeugversionen der Programmiersprachen ML-Stil, Prolog-Stil und OO.
quelle
Glauben Sie nicht, dass es einfacher wäre, die GHC-Quellen zu entfernen, was Sie nicht wollen, als Ihren eigenen Haskell-Interpreter von Grund auf neu zu schreiben? Im Allgemeinen sollte das Entfernen von Features viel weniger Aufwand erfordern als das Erstellen / Hinzufügen von Features.
GHC ist sowieso in Haskell geschrieben, technisch gesehen bleibt das bei Ihrer Frage nach einem in Haskell geschriebenen Haskell-Dolmetscher.
Es wäre wahrscheinlich nicht allzu schwierig, das Ganze statisch zu verknüpfen und dann nur Ihr angepasstes GHCi zu verteilen, damit die Schüler keine anderen Haskell-Quellmodule laden können. Ich habe keine Ahnung, wie viel Arbeit erforderlich wäre, um zu verhindern, dass andere Haskell-Objektdateien geladen werden. Vielleicht möchten Sie auch FFI deaktivieren, wenn Sie eine Reihe von Betrügern in Ihren Klassen haben :)
quelle
Der Grund, warum es so viele LISP-Interpreter gibt, ist, dass LISP im Grunde ein Vorgänger von JSON ist: ein einfaches Format zum Codieren von Daten. Dies macht das Frontend-Teil ziemlich einfach zu handhaben. Im Vergleich dazu ist Haskell, insbesondere bei Spracherweiterungen, nicht die am einfachsten zu analysierende Sprache. Dies sind einige syntaktische Konstrukte, die schwierig zu klingen klingen:
do
- Blockiert und Desugaring zu monadischem CodeJedes dieser Probleme, mit Ausnahme der Bediener, könnte von den Studenten nach ihrem Compiler-Konstruktionskurs angegangen werden, aber es würde den Fokus von der tatsächlichen Funktionsweise von Haskell ablenken. Darüber hinaus möchten Sie möglicherweise nicht alle syntaktischen Konstrukte von Haskell direkt implementieren, sondern stattdessen Durchläufe implementieren, um sie zu entfernen. Das bringt uns zum wörtlichen Kern des Themas, Wortspiel voll beabsichtigt.
Mein Vorschlag ist, Typechecking und einen Interpreter für
Core
anstelle von vollständigem Haskell zu implementieren . Beide Aufgaben sind für sich genommen schon recht kompliziert. Diese Sprache ist zwar immer noch eine stark typisierte funktionale Sprache, aber im Hinblick auf Optimierung und Codegenerierung viel weniger kompliziert zu handhaben. Es ist jedoch immer noch unabhängig von der zugrunde liegenden Maschine. Daher verwendet GHC es als Zwischensprache und übersetzt die meisten syntaxischen Konstrukte von Haskell in sie.Darüber hinaus sollten Sie nicht davor zurückschrecken, das Frontend von GHC (oder einem anderen Compiler) zu verwenden. Ich würde das nicht als Betrug betrachten, da benutzerdefinierte LISPs den Parser des Host-LISP-Systems verwenden (zumindest während des Bootstrapings). Wenn Sie
Core
Snippets bereinigen und den Schülern zusammen mit dem Originalcode präsentieren, können Sie einen Überblick darüber geben, was das Frontend tut und warum es vorzuziehen ist, es nicht erneut zu implementieren.Hier sind einige Links zur Dokumentation von
Core
GHC:Core
Typquelle