CMU Common Lisp Einf¨uhrung

Werbung
CMU Common Lisp Einführung
M. Löthe, S. Klatt
(überarbeitet von Mark Giereth am 14. Mai 2003)
Inhaltsverzeichnis
1
2
CMU Common Lisp Programmierumgebung
1.1 CMU-CL Lisp im Emacs . . . . . . . . .
1.2 Dateibefehle im Emacs-Lispmodus . . . .
1.3 Befehle im Lisp-Shell Puffer . . . . . . .
1.4 CMU-CL Top-Level Befehle . . . . . . .
1.5 Fehler und Warnungen . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
2
2
3
3
4
5
Common Lisp Kurzreferenz
2.1 Evaluierung von Ausdrücken .
2.2 Printed Representation . . . .
2.3 Funktionen und ihre Parameter
2.4 Zuweisungen . . . . . . . . .
2.5 Logik und Verzweigungen . .
2.6 Schleifen . . . . . . . . . . .
2.7 Vergleichsprädikate . . . . . .
2.8 Listenbefehle . . . . . . . . .
2.9 Funktion als Datentyp . . . . .
2.10 Stringbearbeitung . . . . . . .
2.11 Zahlen . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
5
5
6
7
7
8
9
11
11
13
14
14
.
.
.
.
.
.
.
.
.
.
.
1
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
1 CMU Common Lisp Programmierumgebung
1.1 CMU-CL Lisp im Emacs
Dieses Blatt erklärt die Bedienung der Arbeitsumgebung CMU Common Lisp (CMUCL), die auf den Linux-Rechnern des Grundstudiums-Pools intalliert ist. CMU-CL ist
eine Common Lisp-Implementierung der Carnegie Mellon Universität. Die Programmierumgebung in CMU-CL besteht aus dem Lisp-Interpreter, der aus einer Shell bzw.
einer Shell im Emacs gestartet werden kann. Im Folgenden wird die Benutzung im
Emacs beschrieben.
Abkürzungen für Emacs-Tastenkombinationen:
C-<Buchstabe> Controltaste + <Buchstabe> gleichzeitig
M-<Buchstabe> Meta-Taste (Alt, oder Esc) + <Buchstabe> nacheinander
Sh-<Buchstabe> Shift-Taste + <Buchstabe> gleichzeitig
Prinzipielle Vorgehensweise :
1. Emacs starten
2. Shell starten mit M-x shell
3. Eingabe des Kommandos lisp
4. Liegt die Programmdatei bereits vor, mit dem Emacs-Befehl ”Open File” [C-x C-f]
öffnen, sonst in einem neuen Puffer (nicht dem Lisp-Shell Puffer !) den Programmcode erstellen, editieren und abspeichern.
WICHTIG: nach jeder Änderung am Programmcode diesen speichern. CMU-CL
lädt sonst die alte Version der Datei und gibt dann wieder den gleichen Fehler
zurück wie vor der Änderung, was meist längeres Suchen nach der Ursache zu
Folge hat.
5. Datei in den Lisp-Shell Puffer laden : (load ¨ <dateiname>¨ )
In <dateiname> muß zusätzlich auch noch der Pfad angegeben werden, sofern sich die Datei nicht im Hauptverzeichnis befindet.
WICHTIG : jedes geänderte Programm wieder mit (load ¨ <dateiname>¨ )
in den CL-Puffer laden, sonst kommt es zu dem gleichen Phänomen wie oben
beschrieben.
6. Beim Auftauchen von Fehlern (beim Laden oder beim Ausführen einer Prozedur) Programmcode verändern (im jeweiligen Puffer), abspeichern, laden,. . . (zur
Fehlerbehandlung siehe Kap. 1.5)
7. Lisp verlassen mit Kommando (quit).
8. Shell verlassen mit Kommando exit.
9. Emacs verlassen mit C-x C-c.
2
1.2 Dateibefehle im Emacs-Lispmodus
Die folgenden Befehle werden in dem Puffer, in dem sich die Programmdatei befindet,
ausgeführt. Man muß kein Emacs-Profi sein, um mit CMU-CL arbeiten zu können.
Gewisse Tastenkombinationen können sich beim Debugging jedoch als sehr wertvoll
erweisen. Hier nun eine Auswahl der wichtigsten:
TAB
Rückt den Code sinnvoll ein. Code sollte immer eingerückt
werden, denn die Einrückung ist leichter zu prüfen als
Klammern zu zählen.
C-g
Quit. Bricht Ausführung des gegenwärtigen Emacs-Befehls
ab.
)
Beim Schließen einer Klammer springt der Cursor kurz
zur entsprechenden öffnenden zurück. Zur Überprüfung
der Klammerung entfernt man die ) und beobachtet beim
erneuten Einfügen den Cursor.
Pufferbefehle
C-x b
zu Puffer wechseln
C-x f
Datei in Puffer laden
C-x s
Puffer in Datei speichern
C-x w
Puffer speichern unter . . .
C-x i
Datei an Cursorposition einfügen
C-x 1
Nur ein Puffer – der aktive – wird im Fenster dargestellt
C-x 2
Das Fenster wird horizontal in zwei Hälften geteilt. Oben
erscheint der aktive Puffer, unten der in der Pufferliste folgende. Sinnvolle Kombination: Programmdatei und Lisp-Shell
Puffer
Search / Replacebefehle
C-s <Ausdruck>
<Ausdruck> wird im Puffer gesucht. Suchrichtung : vorwärts.
Erneutes Betätigen von C-s führt zum nächsten Vorkommen von <Ausdruck> im Puffer.
C-r <Ausdruck>
wie C-s, aber Suchrichtung rückwärts
M-x replace-string
ersetzt im gesamten Puffer <Ausdr1> durch <Ausdr2>
1.3 Befehle im Lisp-Shell Puffer
Mit den CMU-CL-Befehlen kann man im Lisp-Shell-Puffer das CMU-CL-Image
steuern.
3
C-c C-c
momentan ausgeführte Funktion abbrechen.
Dann unbedingt mit 1 (abort) fortfahren. Bei Fortsetzung der Funktionsabarbeitung mit 0 (continue) hilft
danach nur noch der Notausstieg (Puffer schließen mit
C-x k und Lisp-Shell Puffer neu anlegen, wie unter Kapitel 1 beschrieben).
C-↑, C-↓
Tastaturpuffer. Durch C-↑ erscheint die letzte Eingabe wieder am Prompt. Mehrmaliges Betätigen führt zur vorletzten,. . . Eingabe. Mit C-↓ kehrt man diese Suchrichtung um.
1.4 CMU-CL Top-Level Befehle
Die Top-Level-Schleife (read-eval-print-loop) ist die Hauptschnittstelle zwischen Benutzer und CMU-CL-Image. Sie liest die Eingabe des Benutzers, wertet sie aus und
zeigt das Ergebnis an.
Treten Fehler bei der Abarbeitung eines Programms auf, geht CMU-CL in den debugModus. Dies ist insofern von Bedeutung, als daß man in diesem Modus nur die Befehle
zum Stack-Debugging und zum Tracing ausführt und dann mit meistens 0 in den TopLevel zurückkehrt.
Datei- und Verzeichnisbefehle
(load ‘‘<Dateiname>‘‘) angegebene Datei(en) laden.
(compile-file ‘‘<Dateiname>‘‘) angegebene Datei(en) compilieren. Ergebnis: Dateien gleichen Namens, aber mit dem Suffix ’.x86f’.
Compilierter Code läuft schneller als interpretierter.
(quit)
beendet den Lisp-Prozess.
Stack-Debugging-Befehle
Der Stack ist der Aufrufstapel der ausgeführten Funktionen. Bei einem Fehler erkennt
man am Stack, welche Funktion beim Abbruch gerade ausgeführt wurden. Diesen
Stack kann man durchwandern und lokale Variablenwerte u.ä. überprüfen (bei CMUCL derzeit ein Mysterium).
Tracing
(trace <Funktionsname>)
Nimmt die Funktion in die Liste der zu protokollierenden Funktionen auf. Jeder Aufruf solch
einer Funktion wird am Bildschirm angezeigt.
(trace)
zeigt die Liste aller zu protokollierenden Funktionen an.
(untrace <Funktionsname>)
entfernt die Funktion aus der Liste. Wird <Funktionsname> nicht angegeben, wird die gesamte
Liste gelöscht.
4
1.5 Fehler und Warnungen
Beim Laden des Programms
End-of-File on #<Stream for file ...>
Tritt dann auf, wenn eine schließende Klammer oder ein Anführungszeichen fehlt und
der Lisp-Evaluator diese bis zum Dateiende sucht, aber natürlich nicht findet.
Andere Ladefehler liegen meist daran, daß der Dateiname falsch geschrieben wurde
oder die Datei an falschen Stellen die Zeichen “.” bzw. “,” enthält und sind selbsterklärend.
Während des Programmlaufs
Warning: Declaring <...> special.
Geschieht z. B. bei erstmaliger Variablenzuweisung mit setq. Am besten Ignorieren.
Error : the variable <...> is unbound
Error : the function <...> is undefined
Wird meist durch einen Tippfehler im Variablen- bzw. Funktionsnamen ausgelöst.
Die meisten anderen Fehlermeldungen entstehen durch Klammerfehler, z.B.
Error: Wrong argument count, wanted 1 and got 2
Error: Illegal function call
Deshalb : Klammerung überprüfen und immer sauber einrücken.
Nach der Fehlermeldung erscheint ein Menü, aus dem man bestimmte Aktionen auswählen
kann, die den Grund des Fehlers beheben sollen. Die Auswahl der Optionen erfolgt
durch Eingabe von :continue, gefolgt von der entsprechenden Nummer. In CMUCL ist meistens nur eine Rückkehr zum Top-Level möglich.
2 Common Lisp Kurzreferenz
Ein Symbol ist eine Folge alphanumerischer Zeichen, die nicht mit einer Ziffer beginnt,
kann also sowohl Variable als auch Funktionsbezeichner sein. Beispiel : x,abc,defun
Ein Ausdruck ist ein Symbol, eine Zahl oder eine aus diesen zusammengesetzte Liste.
Listen werden in Klammern eingeschlossen. Beispiel: (summe 1 2)
Mit Rumpf wird eine Folge von zusammengesetzten Ausdrücken bezeichnet. In ihm
sind die eigentlichen Programmanweisungen enthalten.
Mit <. . . > markierte Befehlsteile stehen nicht wörtlich sondern sind Variablen; . . . heißt
“analog fortsetzen”. Mit [. . . ] gekennzeichnete Befehlsteile sind optional.
2.1 Evaluierung von Ausdrücken
Ein Ausdruck in Common Lisp ist ein Symbol oder eine Liste der Form :
( <Symbol> <Ausdruck1> . . . <AusdruckN>)
• Ein Symbol evaluiert zu seinem Variablenwert.
5
• Wert eines Ausdrucks mit ’ (Quote) ist der Ausdruck selbst (ohne den Quote).
• Bei einer Liste prüft Common Lisp, ob <Symbol> der Name einer sogenannten CL-Spezialform ist (z.B. if, cond, let). Falls ja, werden die Folgeausdrücke
abhängig von dieser Spezialform interpretiert (bei let würde Common Lisp in
<Ausdruck1> beispielsweise die Definition der lokalen Variablen erwarten).
• Ansonsten wird <Symbol> als Name einer Funktion betrachtet, die die folgenden Ausdrücke als Argumente erhält. Zunächst werden <Ausdruck1> bis <AusdruckN> nach diesen Regeln ausgewertet und dann die in <Symbol> definierte
Funktion mit den Werten als Parameter aufgerufen.
Quoting
Wird einem Ausdruck ein Quote (’) vorangestellt, führt das dazu, daß die normale Auswertungsstrategie von Common Lisp nicht angewendet wird. Der Wert des quotierten
Ausdrucks ist vielmehr der Ausdruck selbst, ohne weitere Evaluation darin vorkommender Symbole.
>(setq x 5)
5
>(setq y x)
5
>y
5
>(setq z ’x)
x
>z
x
Die zweite wichtige Verwendung des Quote ist die abkürzende Angabe einer Listenkonstante. Folgende äquivalente Definitionen bauen die Liste mit den Elementen a, b
und c auf:
(cons a (cons b (cons c nil)))
’(a b c)
Kommentare: Eine Zeile: ; <Kommentar> Bereich: #| <Kommentar> |#
2.2
Printed Representation
Lisp-Objekte können komplexere Datenstrukturen wie z. B. Listen sein. Damit diese
Objekte auf dem Bildschirm ausgegeben bzw. von dort eingelesen werden können,
müssen sie textuell irgendwie dargestellt werden können. Diese Darstellung wird als
die printed representation bezeichnet. Sie wird von den beiden Prozeduren print
und read verwendet, um die Aus-/Eingabe zu realisieren.
6
2.3 Funktionen und ihre Parameter
(defun <name> (<parameter>) <Rumpf>)
Definiert eine (benannte) Funktion mit Namen <name> und der Parameterliste (Lambdaliste) (<Parameter>). Der <Rumpf> enthält die Ausdrücke, die beim Aufruf der
Funktion aufgerufen werden. Funktionswert ist der Wert des letzten Ausdrucks.
Im Rumpf dürfen die Parameter verwendet werden; die beim Aufruf übergebenen Argumente werden an die in der Parameterliste definierten Variablen gebunden. Normalfall ist der Pflichtparameter, für den man einfach den Namen in die Parameterliste
einträgt. Es gibt noch weitere Typen, z.B.:
(defun argtest (a b &optional (c 3) d &rest e)
(format t "a: ˜a b: ˜a c: ˜a d: ˜a e: ˜a" a b c d e))
• a,b sind Pflichtparameter (required parameters). Beim Aufruf von argtest
wird jeder an genau ein Argument gebunden. Jeder Aufruf von argtest muß
mindestens zwei Argumente bereitstellen, sonst kommt es zu einer Fehlermeldung.
• c,d sind optionale Parameter. Dazu wird ihnen das Schlüsselwort &optional
vorangestellt. Sie können, müssen aber nicht beim Aufruf mit Werten belegt
werden. In letzterem Fall besitzt c den vordefinierten Wert 3, d ist nil.
• e ist ein Restparameter. Er sammelt in einer Liste alle übrigen Argumente auf,
die bis dahin noch nicht zugewiesen werden konnten.
• Außerdem gibt es mit &key gekennzeichnete Schlüsselwortparameter
>(argtest 2 4)
a: 2 b: 3 c: 3 d: () e: ()
>(argtest 2)
Error : argtest got 1 arg, wanted at least 2 args
>(argtest 2 4 6 8 10 12 14)
a: 2 b: 4 c: 6 d: 8 e: (10 12 14)
2.4 Zuweisungen
(setq <variable1> <ausdruck1> ...<variableN> <ausdruckN> )
Weist jeder Variablen global den Wert zu, den die Evaluierung des jeweiligen Ausdrucks ergibt. Gibt den Wert des letzten Ausdrucks zurück.
>(setq (a 1) (b (cdr (1 2 3))))
(2 3)
>a
1
7
(setf <ort1> <ausdruck1> ... <ortN> <ausdruckN>)
Ähnlich wie setq, jedoch universeller : <ort> kann nun nicht nur eine Variable sein,
sondern vielmehr die Stelle, auf die <ort> nach deren Evaluierung zeigt, z. B. in einer
Liste. Die meisten vordefinierten Zugriffsfunktionen sind auch zur Verwendung von
setf vorgesehen.
>(setq a (1 2 3))
(1 2 3)
>(setf (car a) w)
w
>a
(w 2 3)
(let ( (<var1> <wert1>)...(<varN> <wertN>)) <Rumpf>)
Belegt die lokalen Variablen <var1> bis <varN> mit den zugehörigen Werten. Diese Belegung gilt jedoch nur innerhalb von <Rumpf>, außerhalb ist sie unwirksam. Ist
bei der Bildung lokaler Variablen setq vorzuziehen. Die Variablen werden hierbei
parallel gebunden (Auswirkungen siehe unten) Gibt den Wert des letzten Ausdrucks
von <Rumpf> zurück.
>(setq a 5)
5
>(let ((a 3) (b 4)) (+ a b))
7
>(let ((a 3) (b (+ a 5)) (+ a b))
13
⇒ parallele Bindung : Im Ausdruck (+ a b) wird der Wert der globalen Variablen
a eingesetzt, die innerhalb des let erfolgte Definition wird nicht berücksichtigt.
(let* ( (<var1> <wert1>)...(<varN> <wertN>)) <Rumpf>)
Wie let, nur werden hier die Variablen sequentiell von links nach rechts gebunden.
>(let ((a 3) (b (+ a 5)) (+ a b))
11
2.5
Logik und Verzweigungen
Die beiden Wahrheitswerte in Common Lisp sind t (wahr) und nil (falsch, auch:
leere Liste).
(not <Bed.1>)
(and <Bed.1> ...<Bed.N>)
(or <Bed.1> ...<Bed.N>)
Entsprechen den bekannten Konstrukten anderer Programmiersprachen und geben t
bzw. nil zurück. Wichtig ist, daß die Bedingungen in Präfix-Notation gestellt werden.
>(and (= 1 2) (> 3 2))
t
8
(if <Bedingung> <then-Zweig> [<else-Zweig>])
Die <Bedingung> wird ausgewertet und der entsprechende Zweig evaluiert. Dabei darf
ein Zweig nur einen einzigen Ausdruck enthalten. Das Ergebnis der Evaluation (bzw.
nil, falls kein Zweig zur Anwendung kam) wird zurückgegeben.
>(if (< 1 2)
(print "Hallo")
(+ 1 2))
"Hallo"
>(if (< 1 2)
(let ((x 3))
(+ x 1)
(+ x 2))
6)
5
(cond (<Bed1> <Zweig1>)
...
(<Bed.N> <ZweigN>)
[(t <else-Zweig> )])
Die Bedingungen werden der Reihe nach ausgewertet und der erste Zweig, dessen Bedingung nicht nil ist, ausgeführt. Jeder Zweig darf mehrere Anweisungen enthalten.
cond liefert den Wert der letzten Anweisung zurück (bzw. nil,vgl. if) und ignoriert
alle folgenden Bedingungsklauseln, auch wenn diese erfüllt wären.
>(cond ((< 1 2)(+ 1 2)(+ 2 3))
((< 1 3)(+ 3 4)))
5
2.6 Schleifen
(loop <Rumpf>)
Endlosschleife. Die Anweisungen in Rumpf werden von links nach rechts abgearbeitet,
nach der letzten wieder mit der ersten begonnen. Kann mit return wieder verlassen
werden. Liefert den Wert zurück, der in der return-Anweisung vorgegeben wurde
bzw. nil, falls kein Wert angegeben ist.
>(setq i 0)
0
>(loop (print’’Hallo’’) (setq i (+i 1)) (if (= i 3) (return
i)))
‘‘Hallo’’
‘‘Hallo’’
9
’’Hallo’’
3
(do ((<Var1> <init1> <step1>)
...
(<VarN> <initN> <stepN>))
(<Abbruchbed> <Enderumpf>)
<Rumpf>)
Die Variablen werden parallel (vgl. let) initialisiert und bei jedem Schleifendurchlauf ebenso parallel durch <step> verändert (s.u.). In <Abbruchbed> ist nur ein einziger Ausdruck zulässig. Ist er erfüllt, werden die Anweisungen in <Enderumpf> ausgeführt. Ansonsten wird <Rumpf> abgearbeitet. Rückgabewert des do ist der Wert der
letzten Klausel im <Enderumpf> oder nil, falls <Enderumpf> leer ist.
Die <step>-Anweisungen greifen immer auf die Werte des vorigen Durchlaufs zurück.
Sei folgende Schleife gegeben :
(do ((x 4 (+ x 2))
(y 3 (+ x 1)))
... )
Bei der Initialisierung wird y an den Wert 3 gebunden. Beim ersten Schleifendurchgang wird y unter Verwendung des alten Wert der lokalen Variablen x(4), als 5 berechnet.Es ergibt sich :
Durchgang x y
1
43
2
6 5 [(+ 4 1)]
3
8 7 [(+ 6 1)] . . .
(do* ((...)) )
Wie do, jedoch werden die Variablen sowohl bei Initialisierung als auch Veränderung
sequentiell gebunden (vgl. let*). Obige Schleife mit do* ergäbe also:
Durchgang x y
1
44
2
67
3
8 9 ...
(dolist (<variable> <Liste> [<Ergebnis>]) <Rumpf>)
Für jedes Element der <Liste> werden die Anweisungen in <Rumpf> ausgeführt, wobei hier der Wert der <variable> an das jeweilige Element gebunden wird. dolist
liefert den Wert des Ausdrucks <Ergebnis> bzw. nil zurück. Mehrere Anweisungen
in <Ergebnis> sind nicht zulässig. (siehe auch : mapcar)
>(dolist (x ’(1 2 3)) (print x))
10
1
2
3
nil
2.7 Vergleichsprädikate
Alle sind gleich, doch einige sind gleicher
(eq <Objekt1> <Objekt2>)
Nur dann wahr, wenn <Objekt1> und <Objekt2> dasselbe Objekt sind (also auf dieselbe Adresse im Speicher zeigen).
(equal <Objekt1> <Objekt2>)
Nur dann wahr, wenn die Objekte die gleiche Struktur besitzen. Faustregel : wenn sie
dieselbe “printed representation” besitzen.
(equalp <Objekt1> <Objekt2>)
Wahr, wenn die Objekte equal sind oder
bei Zeichen : die gleichen Zeichen besitzen (Gross-/Kleinschreibung egal)
bei Zahlen : den gleichen numerischen Wert besitzen
eq
>(eq
>(eq
>(eq
>(eq
>(eq
’a ’a)
’a ’b)
3 3)
3 3.0)
(list ’a ’b)
(list ’a ’b))
>(eq ’(a b)
’(a b))
>(eq "Foo" "Foo")
>(eq "FOO" "foo")
equal
equalp
t
nil
t
nil
t
nil
t
nil
t
nil
t
t
nil
t
t
nil
nil
nil
t
t
nil
t
t
t
(Zahlen vergle
man mit = )
2.8 Listenbefehle
(cons <Element1> <Element2>)
Erzeugt ein Paar mit <Element1> als car und <Element2> als cdr. Die Elemente
selbst sind beliebig und können auch weitere Paare bzw. Listen sein.
>(cons a b) => (a . b)
>(cons a (b c d)) => (a b c d)
(list <Elem1> ...<ElemN>)
Erzeugt eine Liste, die aus den angegebenen Elementen besteht.
11
>(list 1 2 3 a b) => (1 2 3 a b)
>(list (1 2 3) (a b c)) => ((1 2 3) (a b c))
(car <Liste>) (first <Liste>)
Geben das erste Element von <Liste> zurück. Ist die Liste leer, wird () zurückgegeben.
>(car (a b c)) => a
(cdr <Liste>) (rest <Liste>)
Geben eine Liste zurück, die aus allen außer dem ersten Element von <Liste> besteht.
Ist <Liste> leer, wird () zurückgegeben.
>(cdr (a b c)) => (b c)
(second <Liste>), (third <Liste>), (fourth <Liste>), ...,(tenth
<Liste>)
Geben das jeweilige Element von Liste zurück und sind äquivalent zu den entsprechenden car-cdr-Sequenzen,jedoch leichter lesbar.
(nth <n> <Liste>)
Gibt das nte Element der Liste zurück. Das erste Element hat den Index 0. Ist n größer
als die Länge der Liste, wird () zurckgegeben.
>(nth 0 (1 2 3)) => 1
>(nth 3 (1 2 3)) => ()
(append <Liste1> ...<ListeN>)
Fügt die Elemente der einzelnen Listen zu einer neuen Liste zusammen.
>(append ’(1 2 3) ’(a b) ’(r 4))
(1 2 3 a b r 4)
>(append ’(1 2) ’(1 (2 3 4) 5))
(1 2 1 (2 3 4) 5)
(member <Element> <Liste>)
Prüft, ob <Element> in <Liste> vorkommt. Falls ja, wird der Rest von <Liste>, beginnend mit <Element> zurückgegeben, sonst nil. Ist die Liste verschachtelt, wird nur die
oberste Ebene betrachtet.Die Elemente werden per default mit eql verglichen.
>(member 3 (1 2 3 a 3 4))
(3 a 3 4)
(assoc <key> <A-Liste>)
<A-Liste> muss folgendermaßen aufgebaut sein :
((<schlüssel1> <wert1>) (<schlüssel2> <wert2>) ...(<schlüsselN>
<wertN>))
assoc gibt das Schlüssel-Wert-Paar zurück, dessen <schlüssel> auf key paßt, andernfalls nil.
12
>(assoc r ((a 1) (b 2) (r 15)))
(r 15)
>(assoc 1 ((a 1) (b 2) (r 15)))
nil
(listp <Ausdruck>)
Gibt t zurück, falls es sich bei <Ausdruck> um eine Liste handelt, sonst nil.
2.9 Funktion als Datentyp
In Common Lisp ist es möglich, auch Funktionen als Parameter zu übergeben. Mit
#’<Funktionsname> erhält man das Funktionsobjekt. Funktionen, die eine Funktion als Parameter erhalten, nennt man Funktionen höherer Ordnung.
(lambda <Parameterliste> <Rumpf>)
Erzeugt eine Funktion ohne Namen. Die Variablen der <Parameterliste> werden beim
Aufruf an die Argumente gebunden. Danach wird der <Rumpf>, der aus einer (leeren)
Folge von Anweisungen besteht, abgearbeitet. Der Wert, der sich bei der Auswertung
der letzten Anweisung ergibt, wird zurückgegeben.
Namenlose Funktionen sind beim Aufruf von Funktionen höherer Ordnung hilfreich.
>((lambda (x) (* x x)) 7)
49
>(mapcar #’(lambda (x) (* x x)) ’(1 2 3 4 5))
(1 4 9 16 25)
(apply #’<Funktion> <Argumentliste>)
Ruft die Funktion mit den Argumenten aus <Argumentliste> auf und gibt das Ergebnis zurück. Hierbei muß darauf geachtet werden, daß die Parameterliste der Funktion und <Argumentliste> kompatibel sind.
>(apply #’list ’(1 2 3 4))
(1 2 3 4)
>(apply #’sqrt ’(1 2)) => Error : sqrt got 2 args, wanted 1
(funcall #’<Funktion> <Arg1> ... <Argn>)
Wendet <Funktion> auf die <Argumente> an und gibt das Ergebnis zurück. Die hinteren Argumente müssen wie beim gewöhnlichen Aufruf zur Parameterliste passen.
funcall liefert das Ergebnis der Funktion zurück.
>(funcall #’list 1 2 3 4)
(1 2 3 4)
(mapcar #’<Funktion> <Liste>)
wendet <Funktion> auf jedes Element der Liste an und gibt die Ergebnisse in Form
einer Liste zurück. In Verbindung mit lambda ist dieser Befehl sehr universell einsetzbar und recht leistungsfähig.
13
>(mapcar #’abs ’(3 -4 -5)) => (3 4 5)
>(mapcar #’(lambda (x) (* x x)) ’(2 3 4 5 6))
(4 9 16 25 36)
2.10 Stringbearbeitung
Strings werden in Common Lisp als eindimensionales Array von Zeichen repräsentiert. Notiert werden sie als "<inhalt>". Allgemeine Arrays stehen ebenfalls zur
Verfügung. (characterp <Objekt>) (stringp <Objekt>)
Geben t zurück, falls es sich bei <Objekt> um ein Zeichen bzw. einen String handelt
(aref <String> <Index>)
Gibt das Zeichen zurück, das an Stelle <Index> in <String> steht. Der erste Buchstabe hat dabei den Index 0. Das zurückgegebene Zeichen ist kein String, sondern ein
Zeichen. Ist Index kleiner 0 oder grösser als die Länge des Strings, erscheint eine Fehlermeldung. aref kann auch für allgemeine Arrays verwendet werden.
>(aref "abc" 0)
#\a
(concatenate ’string <String1> ... <StringN>)
Fügt die angegebenen Strings zu einem neuen String zusammen (ohne Leerzeichen)
einzufügen. concatenate kann jegliche Art von Sequenzen zusammenfügen, die
auf einen gemeinsamen Datentyp gebracht werden können. Dieser muß dann an Stelle
von ’string angegeben werden.
>(concatenate ’string "abc" "def")
"abcdef"
2.11 Zahlen
Die Operatoren +, -, *, / sind in Common Lisp gewöhnliche Funktionen. Deshalb verwendet man für Zahlenrechnungen die Präfix-Notation.
Den Ausdruck (3 ∗ 4) + ((2 − 1)/3) schreibt man in Lisp als:
(+ (* 3 4)
(\ (- 2 1) 3))
Common Lisp arbeitet intern mit verschiedenen Zahlentypen : fixnum, integer,
complex, rational und floating point. Bei Ausführung arithmetischer
Operationen findet bei Bedarf eine automatische Konversion statt, so daß Zahlen in
verschiedenen Formaten ausgegeben werden. Prädikate
(= <zahl1><zahl2>)
14
Vergleicht die zwei Zahlen auf mathematische Gleichheit – im Gegensatz zu equal
spielt bei = der Typ keine Rolle.
(numberp <Ausdruck>) Prüft, ob es sich bei <Ausdruck> um eine Zahl handelt
und gibt t bzw. nil zurück.
15
Herunterladen