1.4
Wichtige Datentypen
|
|
Wie jede andere moderne Programmiersprache unterscheidet
CL eine große Zahl von Datentypen. Zu
den wichtigsten Datentypen in CL gehören die folgenden:
|
|
Diese Datentypen lassen sich nach verschiedenen
semantischen Kriterien klassifizieren: So bilden z.B. alle
Datentypen mit Ausnahme des Datentyps der Listen die Klasse der atomaren
Datentypen oder kurz der Atome. |
|
Atome |
|
selbstevaluierende
Objekte
|
Zahlen
|
Zeichen
|
Zeichenketten
|
Symbole
|
Streams
|
Strukturen
|
Funktionen
|
Arrays
|
|
Listen werden aus noch
zu erläuternden Gründen auch als
CONSes bezeichnet.
|
|
Conses |
Paarlisten
|
einfache
Listen
|
Assoziationslisten
|
Property
- Listen
|
Listen
|
|
Für einige dieser Datentypen gibt es
verschiedene
Subtypen: So werden z.B. verschiedene Klassen von Zahlen
unterschieden: natürliche Zahlen, reele Zahlen, komplexe Zahlen,
etc.
In vielen Fällen unterscheidet sich die Repräsentation
von Elementen eines Datentyps nicht von der aus anderen Programmiersprachen
vertrauten Repräsentation:
|
|
Beispiele -
Datentypen
|
|
Natürliche Zahlen
|
1 - 37466 0 |
Dezimalzahlen
|
0.0 3.14 6.02+E23 -0.0000000000009 |
Zeichen
|
#\a #\Z #\9 #\( #\= #\Newline |
|
Neben den üblichen alphanumerischen Zeichen
gibt es Zeichen, die nicht direkt sichtbar sind (sogen. whitespace
character) wie z.B. #\Newline und #\Space. Alle Zeichen beginnen
mit einer #\-Kombination. |
|
|
Zeichenketten
|
"Hallo", "Noch ein String"
, "\"" |
|
Zeichenketten können beliebige Zeichen enthalten.
Sie werden durch doppelte Hochkommata
(") begrenzt. Wie das letzte Beispiel zeigt,
kann auch das zur Markierung von Zeichenkettengrenzen verwendete
Zeichen in einem String vorkommen, wenn ihm ein Backslash (\)
vorangestellt wird. |
|
|
Symbole
|
HALLO, Hallo, mein-symbol, datei1.lsp |
|
Symbolbezeichner können aus
beliebigen alpha-numerischen Zeichen und bestimmten Sonderzeichen
gebildet werden, müssen aber mit
einem Buchstaben beginnen. Zwischen Groß- und
Kleinschreibung wird anders als bei Zeichenketten normalerweise
nicht unterschieden. |
|
|
Listen
|
(), (77 listen), (noch (eine (Liste))), (eine
. LISTE?) |
|
Eine nicht-leere Liste kann
Objekte beliebigen Typs enthalten:
Zahlen, Symbole oder auch andere Listen. |
|
|
|
1.5
Conses
|
|
Ein CONS ist ein komplexes Objekt, das durch die geordnete Verbindung
zweier LISP-Objekte gebildet wird, von denen jedes selbst wieder
ein Objekt beliebigen Typs (z.B ein CONS ) sein kann; d.h., CONSes
bilden eine rekursive Datenstruktur. Objekte dieses Typs
werden häufig durch sogen. CONS-Zellen repräsentiert,
die zwei Zeiger enthalten, wobei der erste auf das erste Objekt
und der zweite auf das zweite Objekt weist:
|
|
Es gibt zwei Typen von CONSes:
Listen und Paarlisten (dotted pairs). Der Unterschied zwischen diesen
beiden Typen von CONSes besteht darin, daß bei Listen der CDR-Zeiger
der letzten CONS-Zelle immer auf das die leere Liste repräsentierende
Symbol NIL weist; bei den Paarlisten dagegen auf ein beliebiges LISP-Objekt.
Listen bilden also einen speziellen Subtyp von Paarlisten - es sind
Paarlisten, bei denen der CDR-Zeiger der letzten CONS-Zelle auf NIL
weist.
Um für den Benutzer die Unterscheidung von Listen und Paarlisten
transparent zu gestalten, werden Paarlisten vom System auf dem Bildschirm
anders dargestellt als 'echte' Listen: Bei
der Repräsentation von Paarlisten wird der Punkt "."
verwendet, um die beiden Objekte
der Paarliste voneinander zu trennen; d.h. der Punkt "."
trennt den CAR-Teil vom CDR-Teil einer CONS-Zelle. |
|
Beispiele
CONS
|
(X
. Y) ; Paarliste, die aus den Objekten X und Y
besteht
|
(X
Y) ; Liste, die auch diese Objekte enthält
|
(X
. (Y . Z)) ; Paarliste, die aus X und der Paarliste (Y . Z) besteht
|
(X
Y Z) ; Liste mit den Objekten X, Y, Z
|
|
Tatsächlich lassen sich auch Listen in
dieser Punktnotation darstellen:
|
(X
. (Y . NIL))
|
(X
. (Y . (Z . NIL)))
|
|
|
Allerdings wird diese Repräsentation vom System
direkt in die Standardlistenrepräsentation ohne Punkt überführt.
Durch Verwendung von CONS-Zellen läßt sich die Struktur
von Listen und Paarlisten sehr anschaulich darstellen; die Liste (X
Y Z) z.B. läßt sich so repräsentieren als:
|
|
|
Die Liste besteht in dieser
Repräsentationsform aus drei CONS-Zellen: Der CAR-Zeiger
der ersten weist auf das Objekt X, der CDR-Zeiger auf ein CONS, das
aus den CONS-Zellen 2 und 3 besteht. Der CAR-Zeiger der zweiten CONS-Zelle
weist auf das Objekt Y, der CDR-Zeiger auf ein CONS, das aus der CONS-Zelle
3 besteht, und der CAR-Zeiger der dritten CONS-Zelle weist auf das
Objekt Z, der CDR-Zeiger auf NIL. Dieser Punkt ist, wie schon erwähnt,
entscheidend: Der CDR-Zeiger der letzten
CONS-Zelle einer Liste weist immer auf NIL. So ergibt sich
z.B. für die Liste (X (Y Z)) folgende Struktur: |
|
|
|
Zur Erzeugung von CONSes
gibt es in LISP die Funktion CONS (construct )
|
|
|
CONS
|
CONS Objekt1
Objekt2
|
[Funktion]
|
CONS erzeugt ein komplexes Objekt mit Objekt1
als erster und Objekt2 als zweiter Komponente.
|
|
|
Beispiele
- CONS
|
|
|
(CONS 'A ()) |
|
(A) |
|
|
|
(CONS 'A '(B)) |
|
(A B) |
|
|
|
|
Die Listen (X Y Z) und (X (Y Z)) kann man - statt sie durch
eine Terminaleingabe direkt zu notieren - durch folgende Anweisungen
generieren :
|
|
(CONS
'X (CONS 'Y (CONS 'Z ()))) bzw. (CONS 'X (CONS (CONS 'Y
(CONS 'Z ())) ()))
|
|
Natürlich lassen sich durch CONS nicht nur Listen,
sondern auch Paarlisten generieren: |
|
|
(CONS 'A 'B) |
|
(A . B) |
|
|
|
(CONS 'X (CONS 'Y 'Z)) |
|
(X . (Y . Z)) |
|
|
|
(CONS '(X Y) 'Z) |
|
((X Y) . Z)) |
|
|
Als CONS-Zellen notiert: |
|
|
|
Obwohl Paarlisten den fundamentaleren Objekttyp bilden,
ist für die LISP-Programmierung in vielen
Fällen die Verwendung von Listen vorzuziehen und der
Rückgriff auf Paarlisten nur in bestimmten Situationen sinnvoll
bzw. erforderlich. Manche LISP-ProgrammiererInnen lehnen die Verwendung
von Paarlisten grundsätzlich ab |
|
1.6
Evaluierung von S-Expression
|
|
LISP-Datenstrukturen werden
als S-Expressions (symbolic expressions) bezeichnet. Es
sind nur eine geringe Zahl einfacher semantischer Regeln erforderlich
um festzulegen, wie eine S-Expression zu interpretieren (evaluieren
) ist. |
|
1.6.1 Selbstevaluierende
Objekte
|
Zahlen, Zeichen und Zeichenketten
(strings ) werden als selbstevaluierende Objekte bezeichnet.
Die Evaluierung von S-Expressions dieses Typs, wird durch folgende
Regel bestimmt: |
|
Regel
1
|
Zahlen, Zeichen und Zeichenketten evaluieren
zu sich selbst.
|
|
|
Beispiele - Selbstevaluierende
Objekte
|
|
|
3 |
|
3 |
|
|
|
#\a |
|
#\a |
|
|
|
"Ein alter Hut" |
|
"Ein alter Hut" |
|
|
|
1.62 LISP -
Symbole
|
LISP-Symbole
sind komplexe Objekte, die in Common LISP Implementationen
aus mindestens den folgenden fünf Teilen
bestehen: |
|
|
Print-Name: Der
print-name des Symbols legt den Namen
fest, den das System zur Verwaltung des Symbols verwendet.
Da in Common LISP bei der Bildung von Symbolnamen nicht
zwischen Groß- und Kleinbuchstaben unterschieden
wird (Kleinbuchstaben werden automatisch in Großbuchstaben
konvertiert), besteht der print-name eines Symbols in der Regel
aus Großbuchstaben und anderen in Symbolnamen zulässigen
Zeichen. |
|
|
Beispiele - Symbole (print-name)
|
|
TEILCHENBESCHLEUNIGER
ODER TEilchenBESCHLeunIGER ODER teilchenbeschleuniger
|
|
Drei verschiedene Möglichkeiten,
das Symbol mit dem print-name TEILCHENBESCHLEUNIGER zu bezeichnen.
|
|
*globale-variable*
|
ein-datei.name
|
ein/pfad/name
|
Drei Symbole, deren print-name
Sonderzeichen enthält.
|
|
|
Symbolen können Werte zugewiesen werden, die abhängig
von der Art des Wertes und der Form der Wertzuweisung in dem mit value-binding
, function-binding (im folgenden
auch: Wertbindung bzw. Funktionsbindung ) bzw. property-list
bezeichneten Teil des Symbols gespeichert werden. Wir werden uns zunächst
auf die Wert- und Funktionsbindung von Symbolen beschränken.
|
|
Wertbindung:
Da es möglich ist, Symbolen Werte zuzuweisen, können
sie als Variablen verwendet werden. Als Werte für Symbole sind
beliebige LISP-Objekte zulässig. So kann z.B. der Wert eines
Symbols ein anderes Symbol sein. |
|
|
|
Einige Symbole haben eine vordefinierte
Bedeutung, die durch den Benutzer nicht verändert
werden sollte (System-Konstanten). Die beiden wichtigsten Symbole
dieses Typs sind: |
|
T bezeichnet
den booleschen Wert True ;
|
NIL
bezeichnet den booleschen Wert False (und gleichzeitig auch die
leere Liste).
|
|
Die Evaluation eines Symbols wird durch den Kontext
gesteuert, in dem es vorkommt. Zunächst gilt: |
|
|
Regel
2
|
Wenn keine andere Regel anwendbar ist,
dann evaluiert ein Symbol zu seiner Wertbindung.
|
|
|
Beispiele - Symbole (Wertbindung)
|
|
|
Ausgehend von den links stehenden Wertbindungen, ergeben
sich folgende Resultate:
|
|
PI |
|
(A) |
|
|
|
Name |
|
"Otto Mustermann" |
|
|
|
|
|
|
Die Evaluatierung von Symbolen,
denen zuvor kein Wert zugewiesen wurde, führt zu einer
entsprechenden Fehlermeldung und der Aktivierung eines break-levels. |
|
A |
|
Fehlermeldung
|
|
Wertzuweisung:
Es gibt in Common LISP eine ganze Reihe von Funktionen
bzw. special forms die es ermöglichen, einem
Symbol einen Wert zuzuweisen. In den meisten Fällen
wird die SETQ special form verwendet |
|
|
SETQ
|
SETQ {Symbol
NeuerWert}*
|
[Special Form]
|
|
SETQ nimmt eine Folge von Symbol -NeuerWert
Paaren als Argumente und weist Symbol den Wert von NeuerWert
zu (value-binding ).
Symbol wird nicht evaluiert. Der Wert der letzten NeuerWert
-Form wird als Wert der SETQ-Form zurückgegeben.
|
|
|
Beispiele - Symbole (Wertzuweisung)
|
|
|
|
Während SETQ
nur die Veränderung der Wertbindung von Symbolen erlaubt, ermöglicht
der SETF-Makro (siehe Kapitel
1) auch die Veränderung der Funktionsbindung und der property-list
eines Symbols, sowie den Zugriff auf die Komponenten von
Arrays und Listen. |
|
|
1.6.3 Listen
|
Wenn LISP eine Liste evaluiert, dann werden sequentiell
alle Elemente der Liste evaluiert. Zu beachten ist allerdings, daß
das erste Element der Liste als Funktionsname
und die übrigen Elemente als Bezeichner
der Argumente dieser Funktion aufgefaßt werden. Eine Liste repräsentiert
in diesem Fall also einen Funktionsaufruf. |
Nach Auswertung der Argumentsbezeichner wird die Funktion
auf die Argumente angewendet und der aus der Funktionsanwendung resultierende
Wert wird als Wert der Evaluation der Liste zurückgegeben. |
|
|
Regel
3
|
Wenn ein Symbol als erstes Element einer
zu evaluierenden Liste vorkommt, wird bei der Evaluation der
Liste die Funktionsbindung des Symbols verwendet.
|
Die dort gespeicherte Funktion wird auf
das Resultat der Evaluierung aller übrigen Ausdrücke
der Liste angewendet.Wenn keine andere Regel anwendbar ist,
dann evaluiert ein Symbol zu seiner Wertbindung.
|
|
|
Beispiele - Listen
|
|
|
(+ 9 6) |
Zunächst wird die durch "+" bezeichnete
Funktion lokalisiert (Funktionsbindung
). Dann werden "9" und "6" evaluiert und
anschließend die Funktion auf die errechneten Werte angewendet. |
|
15 |
|
|
|
(+ (- 5 7) 3) |
Zunächst wird die durch "+"
bezeichnete Funktion lokalisiert. Das zweite Element der Liste
ist selbst wieder eine Liste, also wird zunächst die durch
"-" bezeichnete Funktion lokalisiert und anschließend
auf die Werte von "5" und "7" angewendet.
Als Zwischenergebnis erhalten wir -2. Dann wird 3 evaluiert
und mit -2 addiert. |
|
1 |
|
|
|
(8 9 8) |
Bei komplexen Listen wird, wie das letzte Beispiel zeigt,
die Regel 3 rekursiv angewendet. Allerdings
wird jedes Objekt nur einmal evaluiert: evaluiert
z.B. ein Symbol S1 zu einem Symbol S2, wird S2 selbst nicht
wieder evaluiert.
|
|
Fehlermeldung |
da "8" keine Funktion bezeichnet.
|
|
|
Wie die Struktur von Symbolen schon vermuten läßt,
kann ein Symbol gleichzeitig als Variable
und als Funktionsname verwendet werden. |
|
|
1.6.4 Unterdrücken
und Erzwingen einer Evaluierung
|
|
In vielen Fällen ist es sinnvoll, die
Evaluierung von S-Expressions zu verhindern, da sie
zu unerwünschten Resultaten führen würde (z.B. '(8
9 10)'). Zu diesem Zweck gibt es in LISP eine special form mit dem
Namen QUOTE: |
|
|
QUOTE
|
QUOTE Objekt
|
[Special Form]
|
QUOTE verhindert die Evaluierung des LISP-Objekts
Objekt und liefert als Wert Objekt.
|
|
|
|
Da diese special form sehr häufig benötigt
wird, gibt es für sie eine Kurzschreibweise (read-macro ): das
Hochkomma ('). Es gilt also:
|
(QUOTE Object ) = 'Object
|
|
Andererseits gibt es eine Funktion, die wir im Zusammenhang
mit der kurzen Charakterisierung der Funktionsweise des LISP-Interpreters
erwähnt hatten, die eine zusätzliche Evaluierung erzwingt: |
|
|
EVAL
|
EVAL Form
|
[Funktion]
|
Evaluierung; d.h., eine Evaluierung des
Wertes von Form.
|
|
|
Beispiele - Quote / Eval
|
|
|
|
|
|