;;; Konstruktion, Vorlesung vom 05.12.2000 ;;; K10 Datenabstraktion und generische Operationen ;;; K10.1 Abstrakte Datentypen ;;; Der Datentyp "set(X)" sei gegeben durch die Operationen ;;; make-empty-set : (X X -> boolean) (X X -> boolean) -> set(X) ;;; set? : scheme-value -> boolean ;;; set-insert : X set(X) -> set(X) ;;; set-remove : X set(X) -> set(X) ;;; set-elem : X set(X) -> boolean ;;; Die Argumente von (make-empty-set = <) sind eine ;;; Gleichheitsrelation = : X X -> boolean sowie eine ;;; Kleiner-Relation < : X X -> boolean auf den Elementen der Menge. ;;; Zu den Signaturen kommen noch Beziehungen zwischen den ;;; Operationen, wie zB ;;; für alle x und s, (set-elem x (set-insert x s)) == #t ;;; für alle x und s, (set-elem x (set-remove x s)) == #f ;;; Die Signaturen und die Beziehungen zusammengenommen definieren ;;; einen ABSTRAKTEN DATENTYP (ADT) . ;;; Eine IMPLEMENTIERUNG eines ADT A besteht aus ;;; 1. einer Menge M, deren Elemente die Elemente von A repräsentieren ;;; und ;;; 2. Implementierungen der Operationen auf A für M, so dass die ;;; Repräsentation korrekt ist (dh. sie erfüllt die Beziehungen). ;;; Ein abstrakter Datentyp A kann mehrere Implementierungen haben. ;;; Für Elemente des Datentyps set(X) gibt es zum Beispiel folgende ;;; Möglichkeiten: ;;; 1. list-set: list(X) ;;; 2. unique-list-set: list(X) ohne Duplikate ;;; 3. sorted-list-set: list(X) aufsteigend sortiert, ohne Duplikate ;;; 4. btree-set: binärer Suchbaum ;;; ... ;;; K10.1.1 Mengen durch Listen ;;; Repräsentation einer Menge durch ungeordnete Liste der Elemente ;;; mit Wiederholungen. ; Ein list-set(X) ist eine Struktur (define-struct list-set (= list)) ; wobei = : X X -> boolean und list : list(X) ; Dabei ist = eine Gleichheitsrelation auf X. ;;; Definiert: list-set? (define make-empty-list-set (lambda (= <) (make-list-set = '()))) (define list-set-insert (lambda (x s) (make-list-set (list-set-= s) (cons x (list-set-list s))))) (define list-set-remove (lambda (x s) (let ((= (list-set-= s))) (make-list-set = (let loop ((l (list-set-list s))) (if (null? l) '() (let ((y (car l))) (if (= x y) (loop (cdr l)) (cons y (loop (cdr l))))))))))) (define list-set-elem (lambda (x s) (let ((= (list-set-= s))) (let loop ((l (list-set-list s))) (and (not (null? l)) (or (= x (car l)) (loop (cdr l)))))))) ;;; K10.1.2 Mengen durch Listen ohne Wiederholung ; Ein unique-list-set(X) ist eine Struktur (define-struct unique-list-set (= list)) ; wobei = : X X -> boolean und list : list(X) ohne wiederholte Elemente. ; Dabei ist = eine Gleichheitsrelation. ;;; Definiert: unique-list-set? (define make-empty-unique-list-set (lambda (= <) (make-unique-list-set = '()))) (define unique-list-set-insert (lambda (x s) (let ((= (unique-list-set-= s))) (make-unique-list-set = (let loop ((l (unique-list-set-list s))) (if (null? l) (list x) (let ((y (car l))) (if (= x y) l (cons y (loop (cdr l))))))))))) (define unique-list-set-remove '...) (define unique-list-set-elem '...) ;;; K10.1.3 Mengen durch sortierte Listen ohne Wiederholung (define-struct sorted-list-set (= < list)) (define make-empty-sorted-list-set (lambda (= <) (make-sorted-list-set = < '()))) (define sorted-list-set-insert (lambda (x s) '...)) (define sorted-list-set-remove (lambda (x s) '...)) (define sorted-list-set-elem (lambda (x s) '...)) ;;; K10.1.4 Mengen durch binäre Suchbäume (define-struct btree-set (= < tree)) (define make-btree-set (lambda (= <) (make-btree-set = < '()))) (define btree-set-insert (lambda (x s) '...)) (define btree-set-remove (lambda (x s) '...)) (define btree-set-elem (lambda (x s) '...)) ;;; K10.2 Generische Implementierungen ;;; Programme sollten sich nicht auf eine spezifische ;;; Implementierung beziehen, sondern unabhängig davon sein. ;;; Also: Benötigen GENERISCHE SCHNITTSTELLE, die direkt die ;;; Operationen des abstrakten Datentyps benutzt. ;;; Hier: Bei Konstruktion wird die Repräsentation erwähnt. ;;; (aber auch hiervon kann man abstrahieren) ;;; K10.2.1 Datengesteuerte Programmierung (define set? (lambda (s) (or (list-set? s) (unique-list-set? s) (sorted-list-set? s) (btree-list-set? s)))) (define set-insert (lambda (x s) (cond ((list-set? s) (list-set-insert x s)) ((unique-list-set? s) (unique-list-set-insert x s)) ((sorted-list-set? s) (sorted-list-set-insert x s)) ((btree-set? s) (btree-set-insert x s))))) (define set-remove (lambda (x s) (cond ((list-set? s) (list-set-remove x s)) ((unique-list-set? s) (unique-list-set-remove x s)) ((sorted-list-set? s) (sorted-list-set-remove x s)) ((btree-set? s) (btree-set-remove x s))))) (define set-elem (lambda (x s) (cond ((list-set? s) (list-set-elem x s)) ((unique-list-set? s) (unique-list-set-elem x s)) ((sorted-list-set? s) (sorted-list-set-elem x s)) ((btree-set? s) (btree-set-elem x s))))) ;;; Nachteile: ;;; - aufwändig. ;;; - unflexibel: schlecht erweiterbar. ;;; K10.2.2 Message-Passing ;;; SIGNATUR ;;; list->list-set : (X X -> boolean) list(X) -> list-set(X) ;;; list-set(X) = symbol -> ;;; (X -> list-set(X) + X -> list-set(X) + X -> boolean) ;;; ERKLÄRUNG ;;; (list->list-set = l) liefert eine Menge bestehend aus den ;;; Elementen der Liste l unter Verwendung der Gleichheitsoperation =. ;;; Die Repräsentation ist eine Funktion von Symbolen ;;; (Operationsnamen) auf Implementierungen der Operationen ;;; (Funktionen). ;;; DEFINITION (define list->list-set (lambda (= l) (lambda (op) (case op ((insert) (lambda (x) (list->list-set = (cons x l)))) ((remove) (lambda (x) (list->list-set = (let loop ((l l)) (if (null? l) '() (let ((y (car l))) (if (= x y) (loop (cdr l)) (cons y (loop (cdr l)))))))))) ((elem) (lambda (x) (let loop ((l l)) (if (null? l) #f (or (= x (car l)) (loop (cdr l))))))))))) ;;; SIGNATUR ;;; ordered-list->ordered-list-set : ;;; (X X -> boolean) list(X) -> ordered-list-set(X) ;;; ordered-list-set(X) = ;;; symbol -> ;;; (X -> ordered-list-set(X) + X -> ordered-list-set(X) + X -> boolean) ;;; ERKLÄRUNG ;;; (ordered-list->ordered-list-set = < l) liefert eine Menge bestehend ;;; aus den Elementen der aufsteigend sortierten Liste l unter Verwendung ;;; der Gleichheitsrelation = und der Kleiner-Relation <. ;;; Die Repräsentation ist eine Funktion von Symbolen ;;; (Operationsnamen) auf Implementierungen der Operationen ;;; (Funktionen). ;;; DEFINITION (define ordered-list->ordered-list-set (lambda (= < l) (lambda (op) (case op ((insert) (lambda (x) (ordered-list->ordered-list-set = < (let loop ((l l)) (if (null? l) (list x) (let ((y (car l))) (cond ((< x y) (cons x l)) ((= x y) l) (else (cons y (loop (cdr l))))))))))) ((remove) (lambda (x) (ordered-list->ordered-list-set = < (let loop ((l l)) (if (null? l) '() (let ((y (car l))) (cond ((< x y) l) ((= x y) (cdr l)) (else (cons y (loop (cdr l))))))))))) ((elem) (lambda (x) (let loop ((l l)) (if (null? l) #f (let ((y (car l))) (cond ((< x y) #f) ((= x y)) (else (loop (cdr l))))))))))))) ;;; GENERISCHE DEFINITIONEN (define set-insert (lambda (x s) ((s 'insert) x))) (define set-remove (lambda (x s) ((s 'remove) x))) (define set-elem (lambda (x s) ((s 'elem) x))) ;;; Durch diese Definitionen werden die Funktionen set-insert, ;;; set-remove und set-elem ÜBERLADEN, d.h. ihre wirkliche ;;; Implementierung hängt von dem Typ des Arguments s ab. ;;; Erweiterung von Def K1 (Auswertung) ;;; Syntax ;;; ::= ;;; (case ;;; (( ...) ...) ;;; ... ;;; (else ...)) ;;; Der Wert von ;;; (case e0 ((l1 l2 ...) e1 ... em) REST ...) ;;; ist definiert als Wert von ;;; (let ((x e0)) ;;; (cond ;;; ((memv x '(l1 l2 ...)) ;;; (begin e1 ... em)) ;;; (else (case x REST ...)))) ;;; Der Wert von (case e0 (else e1 ... em)) ;;; ist definiert als Wert von ;;; (begin e0 e1 ... em) ;;; Definition von set? durch explizites Typtag: (define-struct objset (obj)) (define unique-list->unique-list-set (lambda (= l) (make-objset (lambda (op) ...)))) (define my-set-insert (lambda (x s) (((objset-obj s) 'insert) x))) ;;; K10.3 Interne Operationen ;;; Erweitere den ADT set(X) um ;;; set-union : set(X) set(X) -> set(X) ;;; Problem: Unterschiedliche Repräsentation der Mengen! ;;; Lösung: Erweitere ADT um Konversionsoperation. ;;; SIGNATUR ;;; set->list : set(X) -> list(X) ;;; ERKLÄRUNG ;;; (set->list s) enthält die Elemente von s ohne Wiederholung. (define set->list (lambda (s) ((s '->list)))) (define set-union (lambda (s1 s2) (list-fold set-insert s1 (set->list s2))))