Es gibt viele Sprachen, die eine Art Metaprogrammierung ermöglichen . Insbesondere wundert es mich, dass keine Antwort auf die Lisp- Sprachfamilie kommt.
Aus Wikipedia:
Metaprogrammierung ist das Schreiben von Computerprogrammen mit der Fähigkeit, Programme als ihre Daten zu behandeln.
Später im Text:
Lisp ist wahrscheinlich der Inbegriff einer Sprache mit Metaprogrammierungsmöglichkeiten, sowohl wegen ihres historischen Vorrangs als auch wegen der Einfachheit und Kraft ihrer Metaprogrammierung.
Lisp-Sprachen
Es folgt eine kurze Einführung in Lisp.
Eine Möglichkeit, Code zu sehen, besteht in einer Reihe von Anweisungen: Tun Sie dies, dann tun Sie das, dann tun Sie das andere ... Dies ist eine Liste! Eine Liste der Aufgaben des Programms. Und natürlich können Listen in Listen enthalten sein, um Schleifen usw. darzustellen.
Wenn wir eine Liste stellen die Elemente a, b, c, d wie folgt enthalten: (ABCD) erhalten wir etwas , das aussieht wie ein Funktionsaufruf Lisp, wo a
die Funktion ist, und b
, c
, d
sind die Argumente. Wenn überhaupt das typische "Hallo Welt!" Programm könnte so geschrieben werden:(println "Hello World!")
Natürlich b
, c
oder d
könnten Listen sein, die auch etwas zu bewerten. Folgendes: (println "I can add :" (+ 1 3) )
würde dann drucken "" Ich kann hinzufügen: 4 ".
Ein Programm ist also eine Serie verschachtelter Listen, und das erste Element ist eine Funktion. Die gute Nachricht ist, dass wir Listen manipulieren können! So können wir Programmiersprachen manipulieren.
Der Lisp-Vorteil
Lisps sind weniger Programmiersprachen als vielmehr ein Toolkit zur Erstellung von Programmiersprachen. Eine programmierbare Programmiersprache.
In Lisps ist es nicht nur viel einfacher, neue Operatoren zu erstellen, es ist auch nahezu unmöglich, einige Operatoren in anderen Sprachen zu schreiben, da Argumente ausgewertet werden, wenn sie an die Funktion übergeben werden.
Beispiel: In einer C-ähnlichen Sprache möchten Sie if
selbst einen Operator schreiben , etwa:
my-if(condition, if-true, if-false)
my-if(false, print("I should not be printed"), print("I should be printed"))
In diesem Fall werden beide Argumente in einer Reihenfolge ausgewertet und gedruckt, die von der Reihenfolge der Auswertung der Argumente abhängt.
In Lisps ist das Schreiben eines Operators (wir nennen es ein Makro) und einer Funktion ungefähr dasselbe und wird auf die gleiche Weise verwendet. Der Hauptunterschied besteht darin, dass Parameter für ein Makro nicht ausgewertet werden, bevor sie als Argumente an das Makro übergeben werden. Dies ist wichtig, um einige Operatoren wie die if
oben genannten schreiben zu können .
Realistische Sprachen
Hier wird gezeigt, wie genau dies nicht der Fall ist. Ich empfehle Ihnen jedoch, das Programmieren in einem einzigen Lisp zu versuchen, um mehr zu erfahren. Sie könnten sich zum Beispiel Folgendes ansehen:
- Schema , ein altes, ziemlich "reines" Lisp mit einem kleinen Kern
- Common Lisp, ein größeres Lisp mit einem gut integrierten Objektsystem und vielen Implementierungen (es ist ANSI-standardisiert)
- Schlagen Sie einen getippten Lisp
- Clojure mein Favorit, die obigen Beispiele waren Clojure-Code. Ein modernes Lisp, das auf der JVM läuft. Es gibt auch einige Beispiele für Clojure-Makros auf SO (aber dies ist nicht der richtige Ausgangspunkt. Ich würde zuerst 4clojure , braveclojure oder clojure koans betrachten ).
Übrigens, Lisp bedeutet LISt Processing.
In Bezug auf Ihre Beispiele
Ich werde Beispiele mit Clojure unten geben:
Wenn Sie eine add
Funktion in Clojure schreiben können, können (defn add [a b] ...your-implementation-here... )
Sie sie +
so benennen (defn + [a b] ...your-implementation-here... )
. Dies ist in der Tat das, was in der realen Implementierung gemacht wird (der Körper der Funktion ist etwas komplizierter, aber die Definition ist im Wesentlichen die gleiche wie ich oben geschrieben habe).
Was ist mit der Infixnotation? Nun, Clojure verwendet eine prefix
(oder polnische) Notation, so dass wir ein infix-to-prefix
Makro erstellen können, das vorangestellten Code in Clojure-Code umwandelt. Welches ist eigentlich überraschend einfach (es tatsächlich eine der ist Makro - Übungen in dem clojure koans)! Es kann auch in freier Wildbahn gesehen werden, siehe z$=
. B. Incanter- Makro .
Hier ist die einfachste Version aus den Koans erklärt:
(defmacro infix [form]
(list (second form) (first form) (nth form 2)))
;; takes a form (ie. some code) as parameter
;; and returns a list (ie. some other code)
;; where the first element is the second element from the original form
;; and the second element is the first element from the original form
;; and the third element is the third element from the original form (indexes start at 0)
;; example :
;; (infix (9 + 1))
;; will become (+ 9 1) which is valid Clojure code and will be executed to give 10 as a result
Um den Punkt noch weiter zu treiben, zitieren einige Lisp :
„Ein Teil dessen, was Lisp auszeichnet, ist, dass es sich weiterentwickeln soll. Mit Lisp können Sie neue Lisp-Operatoren definieren. Wenn neue Abstraktionen populär werden (zum Beispiel objektorientierte Programmierung), ist es immer einfacher, sie in Lisp zu implementieren. Eine solche Sprache gerät wie die DNA nicht aus der Mode. “
- Paul Graham, ANSI Common Lisp
„In Lisp zu programmieren ist wie mit den Urkräften des Universums zu spielen. Es fühlt sich an wie ein Blitz zwischen den Fingerspitzen. Keine andere Sprache fühlt sich so nah an. “
- Glenn Ehrlich, Straße nach Lisp