;;; Konstruktion, Vorlesung vom 07.11.2000 ;;; K7 Rekursive Datenstrukturen ;;; K7.1 Listen ; Eine "list" ist entweder ; 1. empty ; oder ; 2. (cons e l) ; mit e : scheme-value (ein Listenelement) und l : list empty (cons 1 empty) (cons 1 (cons 2 empty)) (cons 1 (cons 2 (cons 3 empty))) ; Die Typen der Listenelemente müssen nicht gleich sein: (cons 1 (cons #t (cons (make-posn 0 0) empty))) ; Abkürzung: (list 1 #t empty) '== (cons 1 (cons #t (cons empty empty))) ; SELEKTOR (first (cons x y)) == x ; SELEKTOR (rest (cons x y)) == y ; TEST (empty? empty) == #t ; TEST (cons? (cons x y)) == #t ; Wirkung wie ; (define-struct empty ()) ; (define-struct cons (first rest)) ; SIGNATUR ; list-length : list -> number ; ERKLÄRUNG ; bestimmt die Anzahl der Listenelemente ; BEISPIEL ; (list-length empty) == 0 ; (list-length (list 1 2 3)) == 3 ; MUSTER (define list-length (lambda (l) (cond ((empty? l) ...) ((cons? l) (... (first l) ... (list-length (rest l)) ...))))) ; DEFINITION (define list-length (lambda (l) (cond ((empty? l) 0) ((cons? l) (+ 1 (list-length (rest l))))))) ; vordefiniert als: length ; list-length ist POLYMORPH in den Elementen der Liste, dh. ; es ist unabhängig von der Sorte der Listenelemente. ; Ein Wert vom Typ "list(number)" ist Wert vom Typ "list", bei dem ; sämtliche Elemente den Typ "number" haben. ; SIGNATUR ; list-add : list(number) number -> list(number) ; ERKLÄRUNG ; (list-add l x) addiert x zu jedem Element von l ; BEISPIEL ; (list-add (list 1 2 3) 0) == (list 1 2 3) ; (list-add (list 1 2 3) 2) == (list 3 4 5) ; MUSTER (define list-add (lambda (l x) (cond ((empty? l) ...) ((cons? l) (... (first l) ... (list-add (rest l) x) ...))))) ; DEFINITION (define list-add (lambda (l x) (cond ((empty? l) empty) ((cons? l) (cons (+ x (first l)) (list-add (rest l) x)))))) ; SIGNATUR ; list-append : list list -> list ; ERKLÄRUNG ; (list-append l1 l2) liefert Liste, in der zuerst die Elemente aus l1 ; auftreten und danach die Element von l2 ; BEISPIEL ; (list-append (list 1 2 3) (list 4 5 6)) == (list 1 2 3 4 5 6) ; (list-append (list) (list 8 4)) == (list 8 4) ; MUSTER (define list-append (lambda (l1 l2) (cond ((empty? l1) ...) ((cons? l1) (... (first l1) ... (list-append (rest l1) l2) ...))))) ; DEFINITION (define list-append (lambda (l1 l2) (cond ((empty? l1) l2) ((cons? l1) (cons (first l1) (list-append (rest l1) l2)))))) ; vordefiniert als: ; append (verallgemeinert auf beliebige Anzahl von Argumenten) ; append ist POLYMORPH in den Elementen der Liste ; (siehe "list" in der Signatur) ; SIGNATUR ; list-reverse : list -> list ; ERKLÄRUNG ; (list-reverse l) liefert Liste, in der die Elemente von l in ; umgedrehter Reihenfolge auftreten ; BEISPIEL ; (list-reverse empty) == empty ; (list-reverse (list 1 2 3 4)) == (list 4 3 2 1) ; MUSTER (define list-reverse (lambda (l) (cond ((empty? l) ...) ((cons? l) (... (first l) ... (list-reverse (rest l)) ...))))) ; DEFINITION (define list-reverse (lambda (l) (cond ((empty? l) empty) ((cons? l) (list-append (list-reverse (rest l)) (list (first l))))))) ; list-reverse ist POLYMORPH in den Listenelementen. ; Ü: Iterative Version list-reverse-it, deren Berechnungsprozess ; eine feste Maximalgrösse besitzt. ;;; K7.2 Eigenschaften von list-append ; Lemma K7.2.1: Es gelten folgende Aussagen ; (i) (list-append xs empty) == xs ; (ii) (list-append empty xs) == xs ; (iii) (list-append xs (list-append ys zs)) == ; (list-append (list-append xs ys) zs) ; Beweis ; (i) durch Induktion über die Definition von "list" ; 1. Induktionsanfang ; (i) gilt für xs == empty ; (list-append empty empty) ; == (cond ((empty? empty) empty) ...) ; == empty ; 2. Induktionsschritt ; Falls (i) gilt für xs ; ==> (i) gilt für (cons x xs), wobei x beliebig ; (list-append (cons x xs) empty) ; == Einsetzen in def von list-append ; (cond ((empty? (cons x xs)) empty) ; ((cons? (cons x xs)) (cons (first (cons x xs)) ; (list-append (rest (cons x xs)) empty)))) ; == Rechenregel für cond ; (cons (first (cons x xs)) ; (list-append (rest (cons x xs)) empty)) ; == Rechenregel für first und rest ; (cons x (list-append xs empty)) ; { nach Induktionsvoraussetzung gilt (i) für xs } ; == (cons x xs) ; { also gilt (i) für (cons x xs) } ; (ii) durch Nachrechnen ; (list-append empty xs) ; == (cond ((empty? empty) xs) ...) ; == xs ; (iii) (list-append xs (list-append ys zs)) == ; (list-append (list-append xs ys) zs) ; durch Induktion nach xs ; 1. Induktionsanfang ; (iii) gilt für xs == empty ; (list-append empty (list-append ys zs)) ; { nach (ii) } ; == (list-append ys zs) ; { nach (ii) } ; == (list-append (list-append empty ys) zs) ; 2. Induktionsschritt ; Falls (iii) gilt für xs ==> (iii) gilt für (cons x xs), wobei x beliebig ; (list-append (cons x xs) (list-append ys zs)) ; == (cons x (list-append xs (list-append ys zs))) ; { nach Induktionsvoraussetzung gilt (iii) für xs } ; == (cons x (list-append (list-append xs ys) zs)) ; == (list-append (cons x (list-append xs ys)) zs) ; == (list-append (list-append (cons x xs) ys) zs) ; Lemma K7.2.2: Es gilt ; (list-append (list-add xs x) (list-add ys x)) ; == (list-add (list-append xs ys) x) ; Beweis durch Induktion über die Definition von "list" ; (über Parameter xs) ; (Übung oder selbst)