Schema vs Common Lisp: Welche Eigenschaften haben in Ihrem Projekt einen Unterschied gemacht? [geschlossen]


155

Sowohl bei StackOverflow als auch auf dieser Site mangelt es nicht an vagen "Scheme vs Common Lisp" -Fragen. Ich möchte diese daher noch genauer fokussieren. Die Frage richtet sich an Personen, die in beiden Sprachen codiert haben:

Welche spezifischen Elemente Ihrer Common-Lisp-Codierungserfahrung haben Sie beim Codieren in Scheme am meisten vermisst? Oder umgekehrt: Was haben Sie beim Codieren in Common Lisp beim Codieren in Scheme verpasst?

Ich meine nicht unbedingt nur Sprachfunktionen. Was die Frage betrifft, sind alle folgenden Punkte zu übersehen:

  • Spezifische Bibliotheken.
  • Besonderheiten von Entwicklungsumgebungen wie SLIME, DrRacket etc.
  • Funktionen bestimmter Implementierungen, wie beispielsweise die Fähigkeit von Gambit, C-Code-Blöcke direkt in Ihre Scheme-Quelle zu schreiben.
  • Und natürlich Sprachfunktionen.

Beispiele für die Art von Antworten, auf die ich hoffe:

  • "Ich habe versucht, X in Common Lisp zu implementieren, und wenn ich die erstklassigen Fortsetzungen von Scheme gehabt hätte, hätte ich einfach nur Y gemacht, aber stattdessen musste ich Z machen, was mehr ein Schmerz war."
  • "Das Skripting des Erstellungsprozesses in meinem Scheme-Projekt wurde immer schmerzhafter, als mein Quellbaum wuchs und ich immer mehr C-Bibliotheken verknüpfte. Für mein nächstes Projekt bin ich zu Common Lisp zurückgekehrt."
  • "Ich habe eine große C ++ - Codebasis, und für mich war die Möglichkeit, C ++ - Aufrufe direkt in meinen Gambit-Schema-Code einzubetten, alle Mängel wert, die das Schema gegenüber Common Lisp aufweisen kann, auch wenn es keine SWIG-Unterstützung gibt."

Ich hoffe also auf Kriegsgeschichten und nicht auf allgemeine Gefühle wie "Schema ist eine einfachere Sprache" usw.


25
Eine ausgezeichnete, gut formulierte Frage. Darauf bin ich selbst neugierig. hoffentlich gibt es da draußen einige Leute mit Fachkenntnissen in beiden Sprachen, die bereit sind, einen Einblick zu gewähren.
Robert Harvey

1
@ Josh K - es ist eindeutig zu beantworten, aber es gibt nicht unbedingt eine einzige endgültige Antwort. Ich wette nur, dass es eine geben wird, weil jemand eine so großartige Antwort herausbringt, dass jeder wie whoa ist!
Glenatron

4
@Josh: Dann kennst du dich vielleicht nicht mit Schema und Common Lisp aus. Beide Sprachen sind für sich genommen sehr mächtig, haben aber keine Akzeptanz im Mainstream. Warum ist das? Es könnte sein, dass es so viele Dialekte gibt; welches wählst du Ein Vergleich dieser Art könnte sehr aufschlussreich sein, und das OP hat die Frage sorgfältig formuliert, um den Umfang auf Antworten zu beschränken, die meiner Ansicht nach sehr spezifisch und beantwortbar sind.
Robert Harvey

13
Leute, schließen Sie die Frage nicht, nur weil Sie sie nicht mögen oder nicht damit in Verbindung bringen können. Es ist eindeutig eine "echte" Frage; Wenn Sie keinen besseren Grund für das Schließen finden, sollten Sie nicht für das Schließen stimmen.
Robert Harvey

4
Sie könnten Richard Stallman eine E-Mail mit seiner Antwort schicken.
Wassimans

Antworten:


100

Mein Grundstudium war Kognitionswissenschaft und Künstliche Intelligenz. Von da an hatte ich eine Ein-Gänge-Einführung in Lisp. Ich fand die Sprache interessant (wie in "elegant"), dachte aber nicht wirklich darüber nach, bis ich viel später auf Greenspuns Zehnte Regel stieß:

Jedes ausreichend komplizierte C- oder Fortran-Programm enthält eine ad-hoc, informell spezifizierte, fehlerbehaftete, langsame Implementierung der Hälfte von Common Lisp.

Greenspuns Argument war (teilweise), dass in vielen komplexen Programmen Interpreter eingebaut sind. Anstatt einen Interpreter in eine Sprache zu integrieren, schlug er vor, dass es sinnvoller sein könnte, eine Sprache wie Lisp zu verwenden, in der bereits ein Interpreter (oder Compiler) integriert ist.

Zu der Zeit arbeitete ich an einer ziemlich großen App, die benutzerdefinierte Berechnungen mit einem benutzerdefinierten Interpreter für eine benutzerdefinierte Sprache durchführte. Ich beschloss, seinen Kern in Lisp als großes Experiment neu zu schreiben.

Es dauerte ungefähr sechs Wochen. Der ursprüngliche Code war ~ 100.000 Zeilen Delphi (eine Pascal-Variante). In Lisp wurde das auf ~ 10.000 Zeilen reduziert. Noch überraschender war jedoch die Tatsache, dass die Lisp-Engine 3-6-mal schneller war. Und denken Sie daran, dass dies die Arbeit eines Lisp-Neulings war! Diese ganze Erfahrung hat mir die Augen geöffnet. Zum ersten Mal sah ich die Möglichkeit, Leistung und Ausdruckskraft in einer einzigen Sprache zu verbinden.

Einige Zeit später, als ich anfing, an einem webbasierten Projekt zu arbeiten, sprach ich eine Reihe von Sprachen vor. Ich habe Lisp und Scheme in die Mischung aufgenommen. Am Ende habe ich eine Schema-Implementierung ausgewählt - Chez-Schema . Ich bin sehr zufrieden mit dem Ergebnis.

Das webbasierte Projekt ist eine leistungsstarke "Auswahlmaschine" . Wir verwenden Scheme auf verschiedene Arten, von der Verarbeitung von Daten über die Abfrage von Daten bis zur Seitenerstellung. An vielen Stellen haben wir tatsächlich mit einer anderen Sprache begonnen, sind aber aus Gründen, die ich im Folgenden kurz beschreiben werde, zu Scheme gewechselt.

Jetzt kann ich Ihre Frage (zumindest teilweise) beantworten.

Während der Audition haben wir uns verschiedene Lisp- und Scheme-Implementierungen angesehen. Auf der Lisp-Seite haben wir uns (glaube ich) Allegro CL, CMUCL, SBCL und LispWorks angesehen. Auf der Schemaseite haben wir uns (glaube ich) Bigloo, Chicken, Chez, Gambit angesehen. (Die Sprachauswahl ist schon lange her. Deshalb bin ich ein bisschen dunstig. Ich kann ein paar Notizen ausgraben, wenn es wichtig ist.)

Von Anfang an suchten wir nach a) nativen Threads und b) Unterstützung für Linux, Mac und Windows. Diese beiden Bedingungen zusammen haben alle außer (ich denke) Allegro und Chez umgehauen. Um die Bewertung fortzusetzen, mussten wir die Multithreading-Anforderungen lockern.

Wir haben eine Reihe kleiner Programme zusammengestellt und diese für Evaluierungen und Tests verwendet. Das ergab eine Reihe von Problemen. Beispiel: Einige Implementierungen wiesen Fehler auf, die verhinderten, dass einige Tests vollständig ausgeführt werden konnten. Einige Implementierungen konnten zur Laufzeit keinen Code kompilieren. Einige Implementierungen konnten zur Laufzeit kompilierten Code nicht einfach in vorkompilierten Code integrieren. Einige Implementierungen hatten Müllsammler, die deutlich besser (oder deutlich schlechter) waren als die anderen. usw.

Für unsere Bedürfnisse haben nur die drei kommerziellen Implementierungen - Allegro, Chez und Lispworks - unsere primären Tests bestanden. Von den dreien bestand nur Chez alle Tests mit Bravour. Zu der Zeit, glaube ich, hatte Lispworks auf keiner Plattform native Threads (ich glaube, das tun sie jetzt), und ich glaube, Allegro hatte auf einigen Plattformen nur native Threads. Darüber hinaus hatte Allegro eine Laufzeitlizenzgebühr, die mir nicht sonderlich gut gefallen hat. Ich glaube, Lispworks hatte keine Laufzeitgebühr und Chez hatte eine unkomplizierte (und sehr vernünftige) Vereinbarung (und diese trat nur in Kraft, wenn Sie den Compiler zur Laufzeit verwendeten).

Hier sind einige Vergleichs- und Kontrastpunkte, die sowohl in Lisp als auch in Scheme etwas bedeutende Codestücke hervorgebracht haben:

  • Die Lisp-Umgebungen sind weitaus ausgereifter. Sie bekommen viel mehr fürs Geld. (Allerdings bedeutet mehr Code auch mehr Fehler.)

  • Die Lisp-Umgebungen sind weitaus schwieriger zu erlernen. Sie brauchen viel mehr Zeit, um kompetent zu werden. Common Lisp ist eine riesige Sprache - und das ist, bevor Sie zu den Bibliotheken kommen, die die kommerziellen Implementierungen hinzufügen. (Trotzdem ist der Syntaxfall von Scheme weitaus subtiler und komplizierter als alles, was in Lisp vorkommt.)

  • In den Lisp-Umgebungen kann es etwas schwieriger sein, Binärdateien zu erstellen. Sie müssen Ihr Image "schütteln", um nicht benötigte Teile zu entfernen. Wenn Sie Ihr Programm während dieses Vorgangs nicht korrekt ausführen, können später Laufzeitfehler auftreten . Im Gegensatz dazu kompilieren wir mit Chez eine Datei der obersten Ebene, die alle anderen benötigten Dateien enthält, und wir sind fertig.

Ich sagte zuvor, dass wir Scheme an einer Reihe von Orten eingesetzt haben, die wir ursprünglich nicht beabsichtigt hatten. Warum? Mir fallen drei Gründe ein.

Zuerst haben wir gelernt, Chez (und seinem Entwickler Cadence) zu vertrauen. Wir haben viel vom Tool verlangt und es lieferte konsequent. Zum Beispiel hatte Chez in der Vergangenheit nur eine geringe Anzahl von Fehlern, und sein Speichermanager war sehr, sehr gut.

Zweitens haben wir gelernt, die Leistung von Chez zu lieben. Wir haben etwas verwendet, das sich wie eine Skriptsprache anfühlte - und wir haben daraus die Geschwindigkeit des nativen Codes gewonnen. Für einige Dinge, die keine Rolle spielten - aber es tat nie weh, und manchmal half es sehr viel.

Drittens haben wir gelernt, die Abstraktion zu lieben, die das Schema bieten kann. Ich meine übrigens nicht nur Makros; Ich meine Dinge wie Verschlüsse, Lambdas, Tail-Calls usw. Sobald Sie anfangen, in diesen Begriffen zu denken, scheinen andere Sprachen im Vergleich eher begrenzt zu sein.

Ist das Schema perfekt? Nein; Es ist ein Kompromiss. Erstens können einzelne Entwickler effektiver arbeiten - für Entwickler ist es jedoch schwieriger, sich gegenseitig den Code zu entlocken, da die Wegweiser der meisten Sprachen (z. B. für Schleifen) im Schema fehlen (z. B. gibt es eine Million Möglichkeiten) eine for-Schleife). Zweitens gibt es einen viel kleineren Pool von Entwicklern, mit denen man reden, die man anheuern, ausleihen usw. kann.

Zusammenfassend würde ich sagen: Lisp und Scheme bieten einige Funktionen, die nirgendwo sonst verfügbar sind. Diese Fähigkeit ist ein Kompromiss, also sollte es in Ihrem speziellen Fall sinnvoller sein. In unserem Fall hatten die entscheidenden Faktoren für die Entscheidung für Lisp oder Scheme mehr mit sehr grundlegenden Funktionen (Plattformunterstützung, Plattformthreads, Laufzeitkompilierung, Laufzeitlizenzierung) zu tun als mit Sprach- oder Bibliotheksfunktionen. Auch in unserem Fall war dies ein Kompromiss: Mit Chez haben wir die Kernfunktionen erhalten, die wir wollten, aber wir haben die umfangreichen Bibliotheken verloren, die die kommerziellen Lisp-Umgebungen hatten.

Um es noch einmal zu wiederholen: Wir haben uns vor langer Zeit die verschiedenen Lisps und Schemata angesehen. Sie haben sich alle seitdem weiterentwickelt und verbessert.


1
Wow, das muss ein wirklich schrecklicher Delphi-Code gewesen sein, wenn er irgendwie 3-6x langsamer war als eine Lisp-Implementierung! :(
Mason Wheeler

2
+1: Das Interessanteste an diesem Beitrag ist die Tatsache, dass Sie von Lisp zu Scheme gewechselt sind, nachdem Sie ein großes Projekt in Lisp durchgeführt haben. (Oder vielleicht habe ich gerade zu lange auf comp.lang.lisp lauern.)
Larry Coleman

25
"Wow, das muss ein wirklich schrecklicher Delphi-Code gewesen sein, wenn er es irgendwie geschafft hat, 3-6x langsamer als eine Lisp-Implementierung zu sein!" Richtig, ich zähle das als mein Scheitern, weil ich es nicht besser erklärt habe. Die Lisp-Implementierung war in der Lage, Benutzerausdrücke in Lisp-Ausdrücke umzuwandeln - ein trivial einfacher Prozess - und dann die Lisp-Ausdrücke in systemeigenen Code zu kompilieren (mit vollständiger Optimierung). Das ist die Bedeutung von Greenspuns Zehnter Regel.
Michael Lenaghan

1
Fantastische Antwort! Ich werde es wählen, zumindest bis ein besseres auftaucht :) Eine Frage: Sie sagen, Sie haben die Entscheidung für das Chez-Programm getroffen, basierend auf dem Stand des Feldes "vor langer Zeit". Könnten Sie ein Jahr angeben?
SuperElectric

11
Der Punkt, dass die LISP-Implementierung frei ist, etwas bis auf den Maschinencode zu kompilieren, anstatt sich auf einen Interpreter zu verlassen, ist subtil und recht nützlich. Das Buch "Let Over Lambda" weist genau darauf hin, warum das portable Common LISP-Regexp-Paket, das die PERL-Regexp-Syntax klont, PERL um einen signifikanten Faktor übertrifft. PERL hat einen Regexp-Interpreter. Das Common LISP-Paket kompiliert die regulären Ausdrücke in Code.
John R. Strohm

37

Normalerweise mag ich es nicht, einen Link als Antwort einzufügen, aber ich habe genau zu diesem Thema einen Blog-Artikel geschrieben. Es ist nicht erschöpfend, bringt aber einige der wichtigsten Punkte auf den Punkt.

http://symbo1ics.com/blog/?p=729

Edit : Hier sind die wichtigsten Punkte:

  1. EXISTENCE : Beide Lisps kamen nach einer Reihe von anderen Lisps. Schema nahm den minimalen, axiomatischen Weg. CL ging den barocken Weg.
  2. CASE : In der Regel unterscheidet Schema zwischen Groß- und Kleinschreibung. CL ist nicht (obwohl es sein kann). Dies wird manchmal übersehen, aber seine Praktikabilität wird (von mir) diskutiert.
  3. NAMEN : Die Namen von Symbolen in CL sind oft seltsam und verwirrend. TERPRI, PROGNEtc. Schema hat in der Regel sehr vernünftige Namen. Dies ist etwas in CL verpasst.
  4. FUNKTIONEN : CL hat einen separaten Funktionsnamensraum. Dies wird im Schema nicht übersehen. Ein einziger Namespace ermöglicht normalerweise eine sehr saubere funktionale Programmierung, die in CL oft schwierig oder umständlich ist. Aber es hat seinen Preis - manchmal muss man Namen wie " list" bis " lst" im Schema verschleiern .
  5. MAKROS : Ich vermisse schmutzige Makros auf niedriger Ebene am meisten im Schema. Ja, syntax-rulesist alles in Ordnung und gut, bis du wirklich ein paar Dinge raushacken willst. Andererseits werden hygienische Makros in CL manchmal übersehen. Keine Standardmethode zu haben, bedeutet, das Rad neu zu erfinden.
  6. PORTABILITÄT : CL ist häufig portabler, obwohl beide Sprachen standardisiert sind. CL ist größer und daher gibt es mehr Standardfunktionen, die ohne externe Bibliotheken verwendet werden können. Dies bedeutet auch, dass mehr implementierungsabhängige Dinge portabel erledigt werden können. Außerdem leidet Scheme unter einer Billion Implementierungen, von denen die meisten etwas inkompatibel sind. Dies macht CL sehr wünschenswert.
  7. BIBLIOTHEKEN : Sehr verwandt mit meinem letzten Punkt. Das Programm hat SRFIs, ist aber nicht allgemein anerkannt. Es gibt keine tragbare Möglichkeit, mit Bibliotheken zu arbeiten. CL dagegen hat Wege. Und Quicklisp ist ein Geschenk Gottes (Xach) - eine Art Aufbewahrungsort für Bibliotheken zur Verwendung.
  8. UMSETZUNGEN : Das Schema leidet unter so vielen Implementierungen. Es gibt keine echte kanonische Implementierung. Auf der anderen Seite bietet CL einige sehr gute Implementierungen für hohe Leistung oder spezifische Verwendung (hohe Leistung: SBCL, kommerziell: Allegro, eingebettet: ECL, portabel: CLISP, Java: ABCL, ...).

Während ich oben nur in der ersten Person gesprochen habe, sollte klar sein, was ich vermisse und was nicht.

[Ich entschuldige mich, wenn diese zu allgemein sind. Es scheint, dass Sie viel spezifischere Details wünschen können. Es gibt einige Besonderheiten in der Post.]


Was ist mit einer (wirklich) kurzen Teaser-Zusammenfassung? ^^
Dave O.

2
Bitte inline die Highlights. Die Antworten sollten selbstständig sein.

1
@ Dave O. und @ Thorbjørn Ravn Andersen: Eine Zusammenfassung wurde wie gewünscht hinzugefügt. Vielen Dank.
Quadrescence

2
"Die Barockstraße"! Was für ein ausgezeichneter Weg, es auszudrücken.
Mark C

Bei Common Lisp wird zwischen Groß- und Kleinschreibung unterschieden, die Eingabe wird jedoch vor der Auswertung in Großbuchstaben umgewandelt. Sie können Kleinbuchstaben in Symbolen erhalten, indem Sie sie in Anführungszeichen setzen. Die Namensfrage ist, weil Scheme die schlechten alten Namen losgeworden ist und CL nicht.
David Thornley

25

Ich habe kürzlich ein Home-Projekt mit einer Bibliothek gestartet, die eine C-Version und eine Java-Version hat. Ich wollte Lisp für das Projekt verwenden und verbrachte ungefähr einen Monat damit, zwischen der Verwendung von Common Lisp, Scheme oder Clojure zu schwanken. Ich habe einige Erfahrungen mit allen drei, aber nur mit Spielzeugprojekten. Ich erzähle Ihnen ein wenig über meine Erfahrungen mit jedem von ihnen, bevor ich Ihnen sage, für welches ich mich entschieden habe.

PLT Racket hat eine nette IDE, mit der Sie nicht nur Ausdrücke aus dem Editor auswerten, sondern auch Klammern anstelle von Parens eingeben und diese gegebenenfalls wieder auf Parens zurücksetzen können. Racket hat auch eine große Anzahl von Bibliotheken mit der Installation und noch mehr zum Download zur Verfügung. Der visuelle Debugger ist ebenfalls hilfreich.

Meine Common Lisp-Implementierung (SBCL) hat keine IDE, aber es ist bei Open-Source-CL-Implementierungen üblich, Emacs und SLIME zu verwenden. Diese Kombination kann sehr effizient sein. Neben der Möglichkeit, Ausdrücke während der Eingabe in die Quelldatei auszuwerten, gibt es auch eine REPL, die alle Bearbeitungsbefehle von Emacs enthält, sodass das Kopieren von Code effizient in beide Richtungen erfolgen kann. Sogar Objekte, die im REPL-Puffer angezeigt werden, können kopiert und eingefügt werden. Alt+(und Alt+)sind effizient für den Umgang mit übereinstimmenden Klammern und Einrückungen.

Alle oben genannten Emacs-Funktionen sind auch für Clojure verfügbar. Meine Bearbeitungserfahrung mit Clojure ähnelt der von Lisp. Das Java-Interop hat gut funktioniert, und ich möchte ein Clojure-Projekt erstellen, sobald es ausgereift ist.

Ich konnte mit allen drei (Common Lisp, Racket und Clojure) auf die Bibliothek zugreifen, entschied mich jedoch für Common Lisp für das Projekt. Ausschlaggebend war, dass das FFI in Common Lisp viel einfacher zu verwenden war. CFFI hat ein sehr gutes Handbuch mit Beispielcode und detaillierten Erklärungen zu jeder Methode. Ich konnte an einem Nachmittag 20 C-Funktionen umbrechen und musste den Code seitdem nicht mehr berühren.

Der andere Faktor war, dass ich mit Common Lisp besser vertraut bin als mit Clojure oder dem R6RS-Schema. Ich habe die meisten Bücher von Practical Common Lisp und Graham gelesen und bin mit dem Hyperspec vertraut. Es ist noch kein "lispy" Code, aber ich bin mir sicher, dass sich das ändern wird, wenn ich mehr Erfahrung sammle.


Danke für das Detail! Verstehe ich Sie richtig, dass Sie dachten, dass der FFI von SBCL einfacher zu verwenden ist als der von Clojure? Wenn ja, wäre ich ziemlich überrascht, da Sie Java-Methoden direkt aus Clojure aufrufen können, ohne sie umbrechen zu müssen. (Oder mussten Sie auch nativen Code aufrufen?)
SuperElectric

6
@SuperElectric: Das Aufrufen von "integrierten" Java-Methoden aus Clojure ist trivial. Aufrufen von Java-Methoden, die sich in einer heruntergeladenen Bibliothek befinden: nicht so sehr. Ich habe wirklich mehr Zeit damit verbracht, die Klassenpfad- und Importzeilen richtig zu machen, als dass ich meine erste C-Methode von SBCL mit CFFI zum Laufen gebracht hätte. Aber ich bin kein Java-Experte, daher kann Ihre Laufleistung variieren.
Larry Coleman

21

Ich programmiere sowohl in CL als auch in Racket.

Ich entwickle gerade eine Website in Common Lisp und habe eine Reihe von internen Programmen für meinen früheren Arbeitgeber in Racket geschrieben.

Für den internen Code entschied ich mich für Racket (damals als PLT-Schema bekannt), da der Arbeitgeber ein Windows-Shop war und ich sie nicht dazu bringen konnte, für LispWorks zu bezahlen. Die einzige gute Open-Source-CL-Implementierung für Windows war (und ist) CCL, für die SSE-Unterstützung im Prozessor erforderlich ist. Der Arbeitgeber, der billig war, verwendete steinzeitliche Hardware. Selbst wenn der Arbeitgeber über angemessene Hardware verfügte, ist McCLIM die einzige GUI-Bibliothek mit Konsequenz in Common Lisp, die nur unter Unix funktioniert. Racket hat eine gute GUI-Bibliothek, die sowohl unter Unix als auch unter Windows funktioniert, was für den Erfolg meines Projekts entscheidend war.

Ich habe über ein Jahr damit verbracht, mich mit dem primitiven DrRacket-Editor auseinanderzusetzen. EMACS konnte die GUI-Version von Racket, damals als MrEd bekannt, unter Windows nicht in ein minderwertiges Lisp verwandeln. Ich musste darauf verzichten, den Ausdruck am Cursor mit einem einzigen Tastendruck auswerten zu können. Stattdessen musste ich den S-Ausdruck manuell auswählen, kopieren, auf das REPL-Fenster klicken (da kein Tastendruck erforderlich ist) und dann den S-Ausdruck einfügen. Ich musste auch auf einen Editor verzichten, der mir die erwarteten Argumente der von mir verwendeten Funktion oder des verwendeten Makros zeigen konnte. DrRacket ist kein Ersatz für SLIME.

Der Arbeitgeber verwendete eine proprietäre Datenbank mit einer komplizierten XML-API, die eine Menge scheinbar unnötiger Informationen erforderte, um auf die Version einer SELECT-Abfrage antworten zu können. Ich habe beschlossen, HTMLPrag zu verwenden, um XML an diese API zu senden und die Antworten zu analysieren. Es hat super geklappt.

Ich musste das überkomplizierte "Syntaxfall" -Makrosystem von Racket erlernen, um ein Makro zu schreiben, mit dem ich mit der überkomplizierten XML-API interagieren und Formulare eingeben konnte, die wie SQL aussahen. Dieser Teil wäre viel einfacher gewesen, wenn ich DEFMACRO zur Verfügung hätte. Das Endergebnis war jedoch immer noch nahtlos, obwohl mehr Anstrengungen erforderlich waren, um es zu erreichen.

Außerdem musste ich auf das LOOP-Makro von Common Lisp verzichten. Racket bot eine Alternative erst an, nachdem ich den größten Teil des Codes geschrieben hatte, und die Alternative ist im Vergleich zu LOOP immer noch mies (obwohl das Entwicklerteam von Racket darauf besteht, dass es besser ist - sie sind einfach falsch). Am Ende habe ich viele benannte LET-Formulare geschrieben, in denen "car" und "cdr" verwendet wurden, um Listen zu durchlaufen.

Apropos Auto und CDR, nichts ist frustrierender als Schemas Interpretation von (auto '()) als Fehler. Ich habe die Groß- und Kleinschreibung von Racket ausgenutzt und CAR und CDR implementiert, die die Semantik von Common Lisp haben. Die Trennung von '() und #f macht es jedoch weitaus weniger sinnvoll,' () als Standardwert zurückzugeben.

Schließlich habe ich UNWIND-PROTECT neu implementiert und mein eigenes Neustart-System erfunden, um die Lücke zu füllen, die Racket hinterlassen hat. Die Racket-Community muss lernen, dass Neustarts sehr nützlich und einfach zu implementieren sind.

Die Let-Values-Form von Racket war zu ausführlich, sodass ich MULTIPLE-VALUE-BIND implementiert habe. Das war absolut notwendig, weil Racket erfordert Sie erhalten alle die Werte , die erzeugt werden, ob Sie sie verwenden oder nicht.

Später habe ich versucht, einen eBay XML API-Client in Common Lisp zu schreiben. Dabei stellte ich fest, dass er nicht mit HTMLPrag vergleichbar ist. HTMLPrag ist verdammt nützlich. Am Ende habe ich dieses Projekt in Racket gemacht. Ich experimentierte mit den Literate Programming-Funktionen von Racket, um herauszufinden, dass ich der einzige Programmierer auf der Erde bin, der es schwieriger findet, richtig geschriebenen Text zu bearbeiten als gewöhnlichen Code oder falsch geschriebenen, übermäßig kommentierten Text.

Mein neues Projekt wird in Common Lisp durchgeführt, was die richtige Wahl war, da die Racket-Community einfach nicht an Parallelität glaubt, was für dieses Projekt von wesentlicher Bedeutung ist. Das einzige, von dem ich dachte, dass ich es von Racket verpasst hätte, waren Fortsetzungen. Ich war jedoch in der Lage, mithilfe von Neustarts das zu tun, was ich brauchte, und im Nachhinein hätte ich es wahrscheinlich mit einem einfachen Abschluss tun können.


2
Ich habe es selbst nicht ausprobiert, aber ich habe Blogposts von Leuten gesehen, die das Kommandozeilen-Schlägerprogramm mit Emacs verwenden. Zum Beispiel: bc.tech.coop/scheme/scheme-emacs.htm
Larry Coleman

5
Um ehrlich zu sein, hört es sich so an, als wären Sie zu Scheme gekommen, um CL zu schreiben, anstatt zu versuchen, Dinge aus einem idiomatischen Schema-POV zu betrachten. Ermutigt das Schema zum Beispiel nicht die Wiederholung, anstatt Schleifen zu verwenden?
Schlitten

@ArtB-Schema regt nicht nur zur Rekursion an, es erfordert sie auch. Das oben erwähnte Projekt hat natürlich eine Menge Rekursion verbraucht. Und das diente nur dazu, Wiederholungen (Sie müssen zum Beispiel eine Kopie des rekursiven Aufrufs in jeden Zweig eines condFormulars einfügen) und Fehler (habe ich den Loop-Terminierungstest damals richtig geschrieben?) Hinzuzufügen. Selbst heute habe ich den Eindruck gewonnen Dieser Schläger ist hauptsächlich für Studenten und nicht für professionelle Programmierer gedacht. Jedes Mal, wenn ich höre, dass jemand außer mir es benutzt, spricht er die Subsprache "Beginning Student" und es ist für eine Klasse.
Konto

Wenn Sie Code über CONDs wiederholen, sagen Sie dann, dass Sie nur eine andere Funktion benötigen?
Schlitten

@ArtB Eine Funktion zum Aufrufen der Schleifenfunktion mit verschiedenen Argumenten? Das wäre irgendwie sinnlos. Sie sehen diese Art der Wiederholung in so gut wie jedem Schema-Code. Es gibt sogar Beispiele in Rackets eigenem Quellcode.
Konto

5

Schema ist mit einer separaten Zusammenstellung konzipiert. Infolgedessen ist die Leistung der Makros häufig stark eingeschränkt, selbst bei Erweiterungen, die ein Defmacro im Common Lisp-Stil anstelle eines schlechten, einschränkenden hygienischen Makrosystems ermöglichen. Es ist nicht immer möglich, ein Makro zu definieren, das ein anderes Makro definiert, das für die sofortige Verwendung in einer nächsten Codezeile vorgesehen ist. Eine solche Möglichkeit ist für die Implementierung effizienter eDSL-Compiler unabdingbar.

Es erübrigt sich zu erwähnen, dass Schema-Implementierungen mit nur R5RS-Hygienemakros für mich kaum nützlich sind, da mein Metaprogrammierungsstil nicht angemessen auf Hygiene übertragen werden kann.

Glücklicherweise gibt es Schema-Implementierungen (z. B. Racket), für die diese Einschränkung nicht gilt.


1
Hallo, ich habe in letzter Zeit angefangen, meine Füße mit Scheme unter Verwendung von Racket nass zu machen. Würde es Ihnen etwas ausmachen, ein kurzes Beispiel für die Verwendung von nicht hygienischen Makros in Racket zu geben? Die Art der verfügbaren Makros scheint einer der umstrittensten Punkte zwischen CL und Schema zu sein.
Orange80

@ orange80, der eine Ansatz besteht darin, docs.racket-lang.org/mzlib/mzlib_defmacro.html zu verwenden . Und natürlich gibt es im R6RS-Modus eine weniger restriktive Möglichkeit.
SK-logic,

@Sk-logic was machst du mit makros die so unhygen sind?
Schlitten

1
@ArtB, ich implementiere eDSLs als Compiler-Funktionen, die mit ihrem Quell-AST sehr viel anfangen können. Hygiene ist bei einem solchen Ansatz ein totales Ärgernis. Sie können sich ansehen, wie es funktioniert: github.com/combinatorylogic/mbase
SK-logic
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.