Destruktive Operationen und Nebeneffekte
Diese Woche haben wir uns weiter mit Listen und Listen Operatoren beschäftigt. Insbesondere haben wir destruktive und nicht-destruktive Operationen miteinander verglichen.
nicht-destruktiv |
destruktiv |
butlast | nbutlast |
reverse | nreverse |
remove | delete |
append | nconc |
cons | push |
subst | nsubst |
substitute | nsubstitute |
Wir haben dann die 2 Arten von destruktiven Nebeneffekten (Side-Effects) kennen gelernt: For-Side-Effects und Recycling.
For-Side-Effect Operationen = Man möchte den Nebeneffekt, z.B. setf
(setf *side-effect* '(a b c)) ; (a b c)
*side-effect* ; (a b c)
(setf (first *side-effect*) '(d e f)) ; (d e f)
*side-effect* ; ((d e f) b c)
Recycling Operationen = Man möchte den Rückgabewert. Beispiel: “n”-Operatoren, wie “nreverse” (“n” steht für non-cons = es werden keine neuen cons-Zellen erzeugt).
(defparameter *reversal* '(1 2 3 4 5))
(setf *reversal* (reverse *reversal*))
=> (5 4 3 2 1)
; Hier wird eine neue Liste gebildet und die alte als *garbage* deklariert. Effizientere Lösung:
(nreverse *reversal*)
=> (5 4 3 2 1) ; Bei nreverse ist es der Funktion erlaubt, die originale Datenstruktur zu verändern (= recyceln)
Cons Zellen
Die Funktion cons
“konstruiert” ein neues Speicherobjekt welches 2 pointers zu Speicheradressen (Werten) enthält. Die erste, oder “linke” Zelle, ist der CAR, die zweite, oder “rechte” Zelle ist der CDR. Da die pointers in den Cons Zellen auf beliebige andere Objekte verweisen können, ist es möglich größere Strukturen aus Cons Zellen zu bauen. Dies ist auch die grundlegende Struktur von Listen in LISP, sie bestehen aus einer Kette von Cons Zellen. Die Elemente der Liste sind in den CARs der Cons Zellen, und die links zu den nachfolgenden Cons Zellen in den CDRs. Der CDR der letzten Cons Zelle in der Kette ist NIL.
(cons 1 2)
=> (1 . 2)
(cons 1 (cons 2 (cons 3 NIL)))
=> (1 2 3)
(list 1 2 3)
=> (1 2 3)
Mapping
Mapping Funktionen sind eine Reihe von Funktionen, die sukzessive mit Elementen einer oder mehrerer Listen als Argumenten ausgeführt (= gemappt) werden. Das Resultat dieser Funktionen werden wiederum als Liste zurückgegeben.
Beispiel: mapcar
ruft eine Funktion mit jedem vorhandenen Element einer Liste auf. Das erste Argument ist eine Funktion und die restlichen Argumente sind Listen, mit denen die Funktion aufgerufen wird.
(mapcar #'1+ '(1 2 3 4 5))
=> (2 3 4 5 6)
(mapcar #'* '(1 2 3) '(4 5 6))
=> (4 10 18)
Besondere Mapping Funktion: reduce
(reduce #'list '(1 2 3 4 5))
=> ((((1 2) 3) 4) 5)
Wer mehr über diese Konzepte erfahren möchte, kann hier nachlesen.