Wenn man als Programmierer nicht einrosten will, sollte man jedes Jahr eine neue Sprache lernen. Wenn's 2000 Java war und 2001 Ruby, warum nicht für 2002 Lisp vorsehen? Man wird viele bekannte Sprachkonstruktionen wiederentdecken, die in Lisp schon jahr(zehnt)elang gang und gäbe sind.
Lisp hilft Programmierzeit zu senken.
Die NASA gab verschiedenen Teams die gleiche Programmieraufgabe in C, C++, Java und Lisp. Es wurden die Programmierzeit, der Speicherbedarf der Programme und die Geschwindigkeit gemessen. Das interessante Ergebnis der Studie [NASA] besagt: Lisps Geschwindigkeit war mit der Geschwindigkeit von C und C++ vergleichbar. Der Speicherbedarf war in etwa wie der von Java, aber die Lisp-Programmierteams hatten mit Abstand als erste die Aufgabe gelöst. In die gleiche Richtung geht der bekannte Artikel [Hindsight]: Mit Accelerating Hindsight: Lisp as a Vehicle for Rapid Prototyping betitelt zeigt er eindrucksvoll die Stärke von Lisp für Rapid Prototyping und wieso das etwas Gutes ist. So manches Projekt hinterlässt einen schlechten Nachgeschmack: Oft weiß man erst, wenn ein Projekt zu Ende ist, wie man es hätte machen sollen. Manager wollen so schnell wie möglich ein richtiges Produkt und keinen Prototypen, aber diese Sichtweise kann sich schnell als nur kurzfristig tauglich herausstellen. Lisp erlaubt es, in sehr kurzer Zeit etwas zu schaffen, das man beurteilen kann, zum Beispiel die Durchführbarkeit eines neuen Ansatzes. Damit bleibt mehr Zeit für die Implementation der Lösung, die sich in dieser Probephase als richtig erwiesen (!) hat. Die vier Hauptpunkte, wieso Lisp gut für Rapid Prototyping ist, sind:- Lisp ist reichhaltig
- Lisp verfügt über generische Funktionen und Message Passing
- Lisp unterstützt modulares Design (unter anderem mit einem Condition-System, Macros, optionalen Deklarationen, Funktionen höherer Ordnung)
- Lisp ermöglicht eine interaktive Entwicklung und Debugging in einer einheitlichen Umgebung
CLISP Installation
Wir haben als Software für diesen Artikel die Open Source Implementation CLisp gewählt. Die zwei bekanntesten kommerziellen Lisp-Implementationen dürften von Xanalys (von Harlequin übernommen) [Xanalys] und Franz [Franz] kommen. Beide bieten auch eine kostenlose Testversion an. Clisp wird am einfachsten per rpm -ih clisp.rpm installiert. Die meisten Linux-Distributionen, wie z.B. Suse liefern automatisch clisp mit. Oder man kompiliert den Sourcecode: 8-10MB Sourcecode herunterladen [CLISP], entpacken, konfigurieren und kompilieren:tar xzvf clisp-2.27.tar.gzcd clisp-2.27./configure --with-module=clx/new-clx --with-module=regexpcd src./makemake --with-module=clx/new-clx --with-module=regexp --with-readline --with-gettext --with-dynamic-ffi > Makefilemake config.lispvi config.lispmakemake check
...(defun short-site-name () "workhorse")(defun long-site-name () "workhorse.approximity.com")...(setq *clhs-root-default* "file:///usr/local/share/doc/HyperSpec/")
[1]> (setq *browser* :lynx):LYNX[2]> (clhs "setq")
> clisp -K <linkset>
Der read-eval-print-loop
Die Interaktion mit einer Lisp-Umgebung geschieht eigentlich immer in dieser klassischen Schleife: Ein LISP-Interpreter liest einen Lisp-Ausdruck, wertet ihn aus, und zeigt das Ergebnis an. Ein Lisp-Ausdruck wird entweder als Funktionsaufruf (mit Klammern) oder als symbolischer Name für einen Wert (ohne Klammern) interpretiert. Namen können prinzipiell jedes beliebige Zeichen enthalten, in der Regel wird zwischen Groß- und Kleinschreibung nicht unterschieden. Mehrteilige Namen werden durch einen Bindestrich gegliedert.[1]> (lisp-implementation-version)"2.27 (released 2001-07-17) (built 3215460179) (memory 3215461181)"[2]> (+ 1 2 (* 2 2))7[3]> *print-case*:UPCASE
Schnupperkurs
Für einen tieferen Einstieg in Lisp empfehlen wir eine der Lisp-Bibeln [Slade, Graham]. Angenehm fällt bei den beiden auf, dass es keine AI-Bücher sind. Wer in AI mit Lisp einsteigen will, sollte [Norvig, Winston] lesen. Eines der besten Nachschlagewerke mit viel Informationen ist nach wie vor [Steele], das auch komplett online [SteeleOnline] verfügbar ist.Obligatorisches Hello, World
Listing 1
[1] > *print-<Tab>*print-array* *print-gensym* *print-radix**print-base* *print-indent-lists* *print-readably**print-case* *print-length* *print-right-margin**print-circle* *print-level* *print-rpars**print-closure* *print-pathnames-ansi* *print-symbols-long**print-escape* *print-pretty*
Atome und Listen
Ein Lisp-Atom ist ein symbolischer Name oder eine Zahl, Listen setzen sich aus Atomen oder Listen zusammen. Das Atom nil und die leere Liste () sind äquivalent, ansonsten gibt es keine Überschneidungen. Die erste Aufgabe des Evaluators "eval" ist es, den Wert eines Atoms zu finden.[1] *print-base*10
[2] (+ 8 8)16[3] (setq *print-base* (+ 8 8))10[4] (+ 8 8)10
Listen manipulieren
Eine Liste setzt sich aus zweiteiligen Zellen zusammen: der erste Teil (car) enthält den eigentlichen Wert und der zweite Teil (cdr) enthält den Rest:[1]> (setq liste (list 1 2 3 4 5))(1 2 3 4 5)[2]> (car liste)1[3]> (cdr liste)(2 3 4 5)[4]> (second liste)2[5]> (elt liste 1)2
Definieren von Funktionen
Funktionen in Lisp haben *sehr* flexible Parameterlisten. Neben notwendigen Parametern können noch optionale Parameter und Schlüsselwort-Parameter, letztere mit Standardwerten, angegeben werden. Schließlich gibt es noch die Möglichkeit, alle noch nicht anderweitig verwendeten Argumente über einen rest-Parameter an die Funktion zu übergeben.Definieren von Funktionen
Funktionen in Lisp haben *sehr* flexible Parameterlisten. Neben notwendigen Parametern können noch optionale Parameter und Schlüsselwort-Parameter, letztere mit Standardwerten, angegeben werden. Schließlich gibt es noch die Möglichkeit, alle noch nicht anderweitig verwendeten Argumente über einen rest-Parameter an die Funktion zu übergeben. Listing 2[1]> (defun square (x) (* x x))SQUARE[2]> (square 9)81[3]> (defun hoch (x optional (y 2)) (expt x y))HOCH[4]> (hoch 3 4)81[5]> (hoch 3)9[6]> (defun potenziere (x key (hoch nil hoch-p))(if hoch-p(expt x hoch)(error "Exponent fehlt")))POTENZIERE[7]> (potenziere 2)*** - Exponent fehlt1. Break [8]> :bt1...1. Break [9]> :h...1. Break [10]> :a
Verzweigungen
Neben dem bekannten (if test-expr true-expr false-expr) und dem Gegenstück (unless test-expr false-expr true-expr) ist die klassische Verzweigung in Lisp die cond-Anweisung, die einem hochgezüchteten case/switch-Statement gleicht.(cond (test-a epxr-a1 expr-a2 ... result-a)(test-b expr-b1 expr-b2 ... result-b)...(t expr-z1 expr-z2 ... result-z))
Rekursive Funktionen
Typisch Lisp sind rekursive Strukturen, die oft elegante Formulierungen ermöglichen (siehe Listing 3). Listing 3[1]> (defun fak (n)(if (zerop n) 1(* n (fak (1- n)))))FAK[2]> (fak 5)120[3]> (trace fak);; Tracing function FAK.(FAK)[4]> (fak 5)1. Trace: (FAK '5)2. Trace: (FAK '4)3. Trace: (FAK '3)4. Trace: (FAK '2)5. Trace: (FAK '1)6. Trace: (FAK '0)6. Trace: FAK ==> 15. Trace: FAK ==> 14. Trace: FAK ==> 23. Trace: FAK ==> 62. Trace: FAK ==> 241. Trace: FAK ==> 120120
Schleifen und Iteratoren
[1]> (dotimes (i 3 "fertig") (print i))012"fertig"[2]> (dolist (i '(a b c) "fertig") (print i))ABC"fertig"
[3]> (do ((i 10 (1+ i))(j 2 (+ j 2)))((> j i) "überholt")(format t "~2d - ~2d~" i j))10 - 211 - 412 - 613 - 814 - 1015 - 1216 - 1417 - 1618 - 18"überholt"
[1]> (mapcar #'print '(a 1 b 2))A1B2(A 1 B 2)
CLOS
Das Common Lisp Object System ist eine sehr mächtige Lisp-Erweiterung, die auf echten generischen Funktionen basiert und überaus flexibel ist, wenn es um die Kombination von Methoden geht (siehe Listing 4). Listing 4[1]> (defclass punkt ()((x :accessor x :initform 0 :initarg :x)(y :accessor y :initform 0 :initarg :y)))#<STANDARD-CLASS PUNKT>[2]>(defun make-punkt (x y)(make-instance 'punkt :x x :y y))MAKE-PUNKT[3]>(setq a (make-punkt 10 20))#<PUNKT #x20373C61>[4]> (setf (x a) 15)15[5]> (x a)15[6]> (defmethod translate ((a punkt) (b punkt))(incf (x a) (x b))(incf (y a) (y b))a)#<STANDARD-METHOD (#<STANDARD-CLASS PUNKT> #<STANDARD-CLASS PUNKT>)>[7]> (translate a (make-punkt 4 8))#<PUNKT #x20373C61>[8]> (defmethod print-object ((p punkt) stream)(format stream "#<(~f/~f)>" (x p) (y p)))#<STANDARD-METHOD (#<STANDARD-CLASS PUNKT> #<BUILT-IN-CLASS T>)>[9]> a#<(19.0/28.0)>
Alle haben von Lisp das beste kopiert, wieso dann noch Lisp lernen?
Kent M. Pitman argumentiert, dass Sprachfeatures ein ökologisches System pictureen, sodass es nicht ausreicht, Sprachen Feature für Feature zu vergleichen. Wesentlich ist die Integration der Elemente in der Sprache. Um Lisp wirklich einschätzen zu können, muss man es eine Zeit lang benützt haben. Hier sind ein paar Pluspunkte, die Pitman [Pitman1, Pitman2] auf Slashdot aufzählte:- Lisp ist dynamisch. Sogar in einem laufenden Image können in einem Debugger Funktionen, Klassen usw. geändert und neu definiert werden. Der laufende Code benützt ab sofort die neuen Methoden. Dies geht sogar, wenn die neue Klasse andere Slots hat, und man kann definieren, wie das Update von den alten auf die neuen für bereits existierende Instanzen gehen soll.
- Lisp ist introspektiv. * Die Syntax von Lisp ist sehr formbar. Lisp erlaubt es Programmierern, die Syntax beliebig umzudefinieren. Nicht umsonst kommt der Name Emacs von Editing macros.
- Lisp erzwingt keine Deklarationen von Variablentypen, wodurch Prototyping schneller wird. Andererseits können Deklarationen in funktionierenden Code eingebettet werden, um die Ausführungsgeschwindigkeit oder den Speicherbedarf zu optimieren.
- Lisp besitzt ein mächtiges Klassensystem und ein flexibles Meta-Klassen System. Das Klassensystem ermöglicht mächtige Slot- und Methodendefinitionen. Das Meta-Klassen System erlaubt es dem Benutzer, das Objektsystem wie Daten zu behandeln, die programmiert werden können, um neue Klassen zu erstellen.
- automatische Speicherverwaltung.
- mächtige integrierte Tools.
Links
- [lisp.org] Association of Lisp Users, www.lisp.org
- [hyperspec] www.lisp.org/HyperSpec/FrontMatter/index.html
- [LispGeschichte1] www8.informatik.uni-erlangen.de/html/lisp/histlit1.html
- [LispGeschichte2] www-formal.stanford.edu/jmc/history/lisp/lisp.html
- [FortranGeschichte] sunsite.univalle.edu.co/fortran/ch1-1.html
- [Erfolg] www.franz.com/success/index.lhtml
- [Viaweb] Beating the averages, www.paulgraham.com/avg.html
- [Sawfish] Sawfish Window Manager, sawmill.sourceforge.net
- [LispMachine] the Lisp Machine: Noble Experiment Or Fabulous Failure?, pt.withington.org/LispM.html
- [Symbolics] kogs-www.informatik.uni-hamburg.de/
- [CLISP] CLISP home, http://clisp.cons.org/
- [NASA] www-aig.jpl.nasa.gov/public/home/gat/lisp-study.html
- [CLASH] CLisp As SHell, clisp.cons.org/clash.html
- [mp3] artists.mp3s.com/artist_song/234/234762.html
- [LispIntro] www.apl.jhu.edu/~hall/lisp.html
- [CLOSsummary] Kurze CLOS Zusammenfassung, www.apl.jhu.edu/~hall/AI-Programming/CLOS-Summary.html
- [CLOS1] rhinos.cl-ki.uni-osnabrueck.de/
- [Xanalys] www.xanalys.com/software_tools/
- [franz] www.franz.com
- [Jscheme] www.cs.brandeis.edu/silk/jscheme/
- [Jfranz] www.franz.com/support/documentation/6.0/doc/jlinker.htm
- [FAQ] www.faqs.org/faqs/lisp-faq
- [accelerating] Accelerating Hindsight, world.std.com/~pitman/PS/Hindsight.html
- [ELisp] Elisp (die Mutter aller Sprachen), www.cs.indiana.edu/elisp/elisp-intro.htm
- [Pitman] slashdot.org/article.pl?sid=01/11/03/1726251 und slashdot.org/article.pl?sid=01/11/13/0420226mode=thread
- [mod_lisp] www.fractalconcept.com
- [SteeleOnline] www-2.cs.cmu.edu/Groups/AI/html/cltl/cltl2.html
Tote Bäume
- [Graham] ANSI Common LISP, Paul Graham, Prentice Hall, 1995
- [Norvig] Paradigms of Artificial Intelligence Programming, Morgan Kaufmann, 1991
- [Winston] Lisp, Patrick Henry Winston, Berthold Klaus Paul Horn, Addison Wesley, 1988
- [Slade] Object-Oriented Common Lisp, Stephen Slade, Prentice Hall 1997
- [Keene] Object-Oriented Programming in Common Lisp: A Programmer's Guide to CLOS, Addison Wesley, 1988
- [Steele] Common Lisp: The Language, Guy L. Steele Jr., 2. Auflage, Digital Press, 1990
Common Lisp Überblick
Common Lisp ist- interaktiv
- ein Lisp für den professionellen Gebrauch
- für konventionelle und AI-Projekte geeignet
- einfach zu testen (interaktiv)
- leicht zu maintainen
- portabel (Es gibt einen Standard für die Sprache und die Bibliotheksfunktionen)
- braucht nur 2MB Speicher)
- implementiert fast den gesamten ANSI Standard, sowie einige Erweiterungen)
- arbeitet mit vi und emacs)
- ist kostenlos)
- klare Syntax und Semantik
- reichhaltige Datentypen: Zahlen, Strings, Arrays, Listen, Characters, Symbols, Structures, Streams, usw.
- runtime typing: Der Programmierer braucht keinen Typendeklarieren, aber er wird benachrichtigt, wenn es Probleme gibt
- viele generische Funktionen: 88 arithmetische Funktionen für alle Art von Zahlen (ganze, rationale, fließkomma- und komplexe Zahlen), 44 Such-, Filter- und Sortier-Funktionen für Listen, Arrays und Strings
- automatische Speicherverwaltung (garbage collection)
- Programme sind in Module packbar
- ein Objekt System, generische Funktionen mit mächtigen Methodenkombinationen
- Makros: Jeder Programmierer kann seine eigenen Spracherweiterungen machen
- einen Interpreter
- einen Compiler, der 5-mal so schnell wie der Interpreter ist
- einen Source-level Debugger, der es erlaubt durch interpretierten Code zu steppen
- alle Datentypen können beliebig groß sein (die Größe wird nie deklariert und kann dynamisch verändert werden)
- beliebig lange Integer
- Beliebig-genaue Arithmetik bei floating point Operationen
- Mehr als 800 Bibliotheksfunktionen und Makros, mehr als 600 davon sind in C geschrieben




