In welchem ​​Bereich ist LISPs Makro besser als Rubys "Fähigkeit", DSL zu erstellen?

21

Eines der Dinge, die Ruby zum Leuchten bringen, ist die Fähigkeit, domänenspezifische Sprachen besser zu erstellen

Obwohl man diese Bibliotheken in LISP über Makros duplizieren kann, finde ich Rubys Implementierung eleganter. Trotzdem denke ich, dass es Fälle gibt, in denen das Makro von LISP besser sein kann als das von Ruby, obwohl mir keines einfällt.

In welchem ​​Bereich ist LISPs Makro besser als Rubys "Fähigkeit", DSL zu erstellen, wenn überhaupt?

aktualisieren

Ich habe das gefragt, weil moderne Programmiersprachen sich der LISP-Singularität nähern , wie

  • C hat einen Präprozessor für die Makroerweiterung , ist jedoch sehr primitiv und fehleranfällig
  • C # verfügt über Attribute, die jedoch schreibgeschützt sind und durch Reflektion verfügbar gemacht werden
  • Python fügte einen Dekorator hinzu, der das Verhalten der Funktion (und der Klasse für Version 3.0) ändern kann, obwohl er sich recht begrenzt anfühlt.
  • Ruby TMTOWTDI, das elegantes DSL macht, wenn Sorgfalt angewendet wird, aber auf Ruby-Weise.

Ich habe mich gefragt, ob das LISP-Makro nur auf Sonderfälle anwendbar ist und ob die anderen Programmiersprachenfunktionen leistungsfähig genug sind, um die Abstraktion zu erhöhen, um den heutigen Herausforderungen in der Softwareentwicklung gerecht zu werden.

OnesimusUnbound
quelle
4
Ich bin mir nicht ganz sicher, warum diesbezüglich enge Abstimmungen stattfinden. Ich denke, das ist die Art von Frage, die wir wollen ? Interessant, zum Nachdenken anregend und der Umfang ist recht gut definiert.
Tim Post
Versuchen Sie, so etwas in Ruby zu implementieren: meta-alternative.net/pfront.pdf
SK-logic
@ Tim Post: Ein Problem ist, dass dies wirklich keine einfache Frage ist, es sei denn, Sie kennen Common Lisp und Ruby gut. Ein weiterer Grund sind die eher unwissenden Verweise auf andere Sprachen, die Puristen ärgern könnten: Es gibt keine Sprache namens C / C ++, und der wesentliche Teil von C ++ ist das Vorlagensystem, und der Vorschlag, dass das Makrosystem von Common Lisp nur auf Sonderfälle anwendbar ist. Grundsätzlich ist es eine gute Frage, aber sie ist schlecht geschrieben und schwer zu beantworten.
David Thornley
@ David Thornley, ich habe den Beitrag aktualisiert, insbesondere über C \ C ++, und den Schwerpunkt auf C gelegt. Was Common Lisp betrifft, hatte ich das Gefühl, dass die Makrofunktion aufgrund der höheren Abstraktion in anderen Programmiersprachen für Sonderfälle gedacht ist. Ich habe die Frage gestellt und gehofft, dass andere mir zeigen werden, dass das CL-Makro nicht für Sonderfälle geeignet ist. Dies ist immer noch eine leistungsstarke Funktion.
OnesimusUnbound
@OnesimusUnbound: Ich würde die Vorlagen von C ++ wirklich in Ihre Liste der Sprachbeispiele aufnehmen, da sie zumindest theoretisch für jede Berechnung geeignet sind, die das Lisp-Makrosystem ausführen kann. Was Lisps Makros angeht, besorgen Sie sich einen guten Common-Lisp-Code (es gibt jede Menge F / OS-Lisp-Code) und suchen Sie nach "defmacro" (Groß- und Kleinschreibung wird nicht berücksichtigt). Sie werden wahrscheinlich eine ganze Menge von ihnen finden. Bedenken Sie, dass Makros schwieriger zu schreiben und richtig zu machen sind als Funktionen, und Sie werden feststellen, dass sie im Allgemeinen nützlich sein müssen.
David Thornley

Antworten:

23

Lies auf Lisp und entscheide dann selbst.

Meine Zusammenfassung ist, dass Ruby eine bessere Syntax bietet. Aber Lisp gewinnt zweifellos mit der Fähigkeit, neue Abstraktionen zu erschaffen und dann Abstraktion auf Abstraktion zu schichten. Aber Sie müssen Lisp in der Praxis sehen, um diesen Punkt zu verstehen. Daher das Buch empfehlen.

btilly
quelle
1
"Let Over Lambda" deckt einen ähnlichen Bereich ab. Auch zum Lesen empfohlen.
John R. Strohm
But Lisp wins, hands down, at the ability to create new abstractions, and then to layer abstraction on abstraction.Jetzt weiß ich warum. . .
OnesimusUnbound
Es ist keine große Sache, über Lisp hinaus irgendeine Art von Syntax bereitzustellen. In der Tat viel einfacher als mit Ruby, dank der Reader-Makros.
SK-logic
1
@ SK-Logik: Richtig. Lispers scheuen sich jedoch vor Lesermakros, denn wenn Sie diesen Weg einmal eingeschlagen haben, fühlt es sich nicht mehr wie ein Lisp an. Einige Varianten von Lisp, wie beispielsweise Clojure, behalten sich Lesermakros für den Sprachdesigner vor.
btilly
14

Rubys Möglichkeiten für DSL-Authoring ändern nichts an der Art der Sprache. Rubys Metaprogrammierungsfunktionen sind von Natur aus an die Syntax und Semantik von Ruby gebunden, und alles, was Sie schreiben, muss in das Objektmodell von Ruby verschoben werden.

Vergleichen Sie dies mit Lisp (und Scheme, dessen Makrofunktionen sich unterscheiden ), in denen Makros auf das abstrakte Programm selbst angewendet werden. Da ein Lisp - Programm ist ein Lisp - Wert, ist ein Makro eine Funktionszuordnung eine im wesentlichen beliebige Syntax zum anderen.

Tatsächlich fühlt sich ein Ruby-DSL immer noch wie ein Ruby an, aber ein Lisp-DSL muss sich nicht wie ein Lisp anfühlen.

Jon Purdy
quelle
6
+1: LOOP fühlt sich nicht sehr Lispy an, als Beispiel für eine DSL.
Frank Shearar
2

Rubys DSLs sind überhaupt keine DSLs, und ich hasse es, sie zu verwenden, weil in ihrer Dokumentation alles darüber steht, wie sie wirklich funktionieren. Nehmen wir zum Beispiel ActiveRecord. Damit können Sie Assoziationen zwischen Modellen "deklarieren":

class Foo < ActiveRecord::Base
    has_one :bar
    has_one :baz
end

Aber die Deklarativität dieses "DSL" (wie die Deklarativität von Rubys classSyntax selbst) ist eine schreckliche Lüge, die jeder entlarven kann, der versteht, wie Rubys "DSLs" tatsächlich funktionieren:

class Foo < ActiveRecord::Base
    [:bar,:baz,:qux,:quux].each do |table|
        has_one table if i_feel_like_it?(table)
    end
    puts "Just for shits and giggles, and to show"
    puts "just how fucked up Ruby really is, we're gonna ask you"
    puts "which SQL table you want the Foo model to have an"
    puts "association with.\n"
    puts "Type the name of a table here: "
    has_one gets.chomp.to_sym
end

(Versuchen Sie einfach, etwas in der Nähe des Körpers einer Lisp- defclassForm zu tun !)

Sobald Sie Code wie den oben genannten in Ihrer Codebasis haben, muss jeder Entwickler im Projekt vollständig verstehen, wie Ruby-DSLs tatsächlich funktionieren (nicht nur die Illusion, die sie erstellen), bevor er den Code verwalten kann. Die verfügbare Dokumentation ist völlig nutzlos, da sie nur die idiomatische Verwendung dokumentiert , die die deklarative Illusion bewahrt.

RSpec ist noch schlimmer als die oben genannten, da es bizarre Edge-Cases gibt, die ein umfangreiches Reverse-Engineering zum Debuggen erfordern. (Ich habe einen ganzen Tag lang versucht, herauszufinden, warum einer meiner Testfälle übersprungen wurde. Es stellte sich heraus, dass RSpec alle Testfälle mit Kontexten nach Testfällen ohne Kontext ausführt , unabhängig von der Reihenfolge, in der sie in der Quelle angezeigt werden , weil die contextMethode Ihren Block in eine andere Datenstruktur legt als normalerweise.)

Lisp-DSLs werden von Makros implementiert, die kleine Compiler sind. Die DSLs, die Sie auf diese Weise erstellen können, sind kein Missbrauch der vorhandenen Syntax von Lisp. Sie sind echte Minisprachen, die nahtlos geschrieben werden können, weil sie ihre eigene Grammatik haben können. Zum Beispiel ist Lisps LOOPMakro viel leistungsfähiger als Rubys eachMethode.

(Ich weiß, dass Sie bereits eine Antwort akzeptiert haben, aber nicht jeder, der dies liest, wird die Gesamtheit von On Lisp lesen wollen .)

Konto wegwerfen
quelle