Dotted pairs sind eine für Lisp ganz typische Erscheinung. Lisp-Datenlisten
werden intern als verkettete Listen abgespeichert, d.h. die einzelnen Nodes
(Verbindungsglieder) liegen irgendwo im Speicher (ähnlich wie die Dateien auf einer
Festplatte, auch die werden immer da gespeichert, wo gerade Platz frei ist).
Jeder Node enthält zwei Zeiger: Der eine davon zeigt auf das eigentliche Daten-Atom,
das wieder woanders im Speicher liegt, der zweite Zeiger verweist auf den
Nachfolger, den nächsten Node.
Ein Zugriff auf eine Liste erfolgt immer so, dass zunächst auf den ersten
Node zugegriffen wird, um dann nacheinander zum jeweils nachfolgenden
Node zu springen, bis das Ziel erreicht wird. Der denkbar einfachste Fall ist
der Zugriff mit
(nth ...), da hier nur mitgezählt wird, wie oft der interne
Listenzeiger auf den Nachfolger umgelenkt wird.
Dotted pairs sind anders aufgebaut als normale Listenstrukturen: Hier wird
kurzerhand der zweite Zeiger des Nodes auf ein Daten-Atom gesetzt. Da ein Node
immer nur zwei Zeiger verwalten kann, ist also kein Platz für irgendwelche
Nachfolger, da beide Zeiger auf Daten verweisen, ist an dieser Stelle immer das
Ende einer Verkettung erreicht. Der erste Zeiger kann auf ein Daten-Atom oder
aber auch auf einen anderen Node zeigen.
(cons '(a b c d) e) => ((a b c d) . c)
; dotted pair als Listenende
Wer bisher nur mit mehr oder weniger einfachen Datenlisten gearbeitet hat, die
er selbst entworfen und strukturiert hat, dem ist vielleicht noch gar nicht
aufgefallen, dass sich dotted pairs mit den meisten Listenfunktionen nicht
bearbeiten lassen. Funktionen wie
(reverse ...) verursachen einen Fehler,
wenn man sie auf dotted pairs anwendet. Will man aber unbekannte Datenlisten
untersuchen, so kommt man nicht umhin, vorher zu testen, ob man es evtl. mit
einem dotted pair zu tun hat.
Anders als bei einer Liste gibt
(cdr ...) bei dotted pairs ein Atom zurück. Da
man aber nicht blind sofort mit
(cdr ...) auf irgendwelche Daten zugreifen kann,
muss man zuerst testen, ob a) überhaupt eine Liste vorliegt, dann muss getestet
werden, ob
(cdr ...) überhaupt einen Listenrest liefert, und erst als drittes
kann geprüft werden, ob der Listenrest ein Atom ist. Dass der Listenrest bei
dotted pairs immer ein Atom sein muss und es bei normalen Listen niemals sein
kann, ergibt sich aus den oben durchgeführten Überlegungen zu den Node-Zeigern.
Wir können jetzt also zur Definition einer hundertprozentig sicheren Testfunktion
kommen:
(defun dotted?(test-item / )
(and
(=(type test-item)'LIST)
(cdr test-item)
(atom(cdr test-item))
)
)
Diese Funktion muss bei allen weiteren Funktionen zur Listenbearbeitung, die
hier noch vorgestellt werden, auf die eine oder andere Weise eingebunden
werden.