In diesem Artikel will ich etwas näher als in der
Übersicht auf Lisp im Allgemeinen
und Common Lisp im Besonderen eingehen. Leider bin ich weit
entfernt davon, ein Lisp Experte zu sein, nichtsdestotrotz
kann vielleicht der eine oder andere Leser ein paar Informationen
herausziehen, die für ihn nützlich sind. Besonders
natürlich diejenigen, die Lisp nur vom Hörensagen
kennen. PräfixnotationWas vielen Programmierern sauer aufstößt bei Lisp,
ist die konsequente Verwendung der Präfixnotation. Beispielsweise
in der Addition, hier der Zahlen 4 und 6, deren Summe einer Variablen
x zugewiesen wird: (setf x (+ 4 6))Das sieht zum Beispiel in Java mit der Infixnotation doch viel gewohnter aus: x = 4 + 6;Aber halt: Die Addition ist ja nun eine der einfachsten Operationen, die es so gibt. Wenn man etwas schwierigeres machen möchte, zum Beispiel eine Potenzierung (also x gleich 4 hoch 6), wie sieht es dann aus? In Common Lisp so: (setf x (expt 4 6))Und in Java: x = Math.pow(4d, 6d);Tja, wo ist denn nun die schöne Infixnotation geblieben? Sobald es komplizierter wird, weichen nämlich fast alle Sprachen ebenfalls auf die Präfixnotation aus (spätestens bei der Deklaration eigener Funktionen). Lisp ist da einfach konsequenter und verwendet diese Art immer. Dadurch muß man nicht lange überlegen, bei einem Funktionsaufruf ist die Funktion immer vorne in der Klammer. KlammernDas fällt wohl jedem auf: In Lisp wimmelt es nur so vor
Klammern. Viele Anfänger weisen das brüsk zurück:
"Ich will doch nicht Klammern zählen müssen!" Hat man sich erst einmal an die vielen Klammern gewöhnt, stören sie kaum noch. ListenDie wichtigste Datenstruktur in Lisp ist die Liste. Es gibt auch
andere, Hashtabellen oder Arrays oder Strings. Aber Listen
sind das Markenzeichen von Lisp, kommt der Name schließlich
von List Processing. Hierzu ein kleines Beispiel, das zwar relativ sinnlos ist,
aber wenigstens anschaulich: (setf willi (+ y (* x 5)))Es wird also einer Variablen willi der Wert zugewiesen, der sich aus der Berechnung (x * 5) + y ergibt. Doch mit einer kleinen Änderung wird etwas ganz anderes daraus: (setf willi '(+ y (* x 5)))Was hat sich geändert? Es ist nur ein kleines Apostroph dazugekommen. Aber das bewirkt, daß der dahinterliegende Ausdruck nicht mehr ausgewertet wird. Statt einer Zahl, die sich aus einer Berechnung ergibt, ist willi jetzt eine Liste, die diese Berechnung durchführt, also ein Programm. Um diese Berechnung ablaufen zu lassen, kann man beispielweise so vorgehen: (eval willi)OK, so würde man das nicht wirklich machen (vor allem ist eval langsam), aber das Prinzip stimmt: Programme und Daten sind für Lisp sozusagen das gleiche. Interaktiv - interpretieren oder compilieren?Lisp ist eine interaktive Programmiersprache. Das bedeutet,
man schreibt zum Beispiel eine Funktion und kann sie sofort
verwenden, ohne langen Compilierzyklus. So kann man jeden
Programmbestandteil schnell testen und nicht erst, wenn das
Programm als Ganzes fertig ist. Weil Lisp interaktiv ist, glauben viele Leute, daß Lisp eine Interpretersprache ist. Tatsächlich kann man aber in Lisp natürlich auch compilieren, und zwar nicht nur das ganze Programm, sondern auch kleine Bestandteile. So wird der Zyklus Schreiben-Testen-Verbessern nicht unnötig lange unterbrochen. Funktionen und funktionale ProgrammierungFunktionen sind in Lisp (wie in den meisten anderen Sprachen auch) sehr wichtig. Das ist ja nun nichts ungewöhnliches, interessant wird es aber hier: In Lisp können Funktionen andere Funktionen als Parameter bekommen oder als Wert zurückliefern. Das geht in C zwar auch, aber nur über Zeiger. Auch nicht uninteressant: Lisp Funktionen können beliebig
viele Werte zurückgeben. Und zwar ohne den Einsatz von Tricks
wie zum Beispiel einer Klasse oder Struktur als Rückgabewert. Kommen wir zur berühmten funktionalen Programmierung. Was
hat es damit auf sich? Dadurch sind verschiedene Funktionen deutlich unabhängiger
voneinander. Man muß sich nicht erst überlegen, welche
Änderungen die Funktion, die man aufrufen will, an irgendwelchen
Objekten vornimmt, denn sie nimmt keine vor. MakrosBei C-Programmiern haben Makros nicht unbedingt den besten Ruf, aber Lisp Makros sind ein ganz anderes paar Schuhe. In C sind Makros primitive Ersetzungsanweisungen an den Präprozessor des Compilers. In Lisp kann man sich mit Makros eine eigene Programmiersprache innerhalb von Lisp erzeugen. So gibt es in Common Lisp keine for-Schleife. Für Schleifen
gibt es die do Konstruktion, die aber nicht unbedingt einfach ist
und meistens visuellen Overkill darstellt. Also kann man sich
ein Makro schreiben, das eine for-Schleife einführt
(entnommen aus "On Lisp" von
Paul Graham): (defmacro for ((var start stop) &body body) (let ((gstop (gensym))) `(do ((,var ,start (1+ ,var)) (,gstop ,stop)) ((> ,var ,gstop)) ,@body)))Und schon gibt es in unserem Lisp eine for-Schleife. Das ist nicht einfach eine Funktion, sondern beim Übersetzen des Programms wird dieses Makro expandiert und in eine andere Befehlsfolge umgewandelt. Makros können noch viel komplexer sein als dieses Beispiel, es ist ein weitaus leistungsfähigerer Mechanismus als ein einfaches Suchen und Ersetzen. Aus diesem Grund wird Lisp auch als programmierbare Programmiersprache bezeichnet. LiteraturDas schon erwähnte On Lisp, darin wird vor allem auf die Erstellung von Makros eingegangen. Ebenfalls von Paul Graham ist "ANSI Common Lisp" mit ausführlicher Referenz von Common Lisp (ISBN: 0-13-370875-6). Ein besonders einsteigerfreundliches, praxisnahes und sehr neues Buch von Peter Seibel ist Practical Common Lisp. Leider scheint es wenige deutschsprachige Bücher zu Common Lisp zu geben, wer ein gutes und aktuelles kennt, möge mir eine Mail schreiben. |