;;; Konstruktion, Vorlesung vom 02.11.2000 ;;; K6 Datenstrukturen mit Varianten ; Jeder Wert von Scheme (scheme-value) trägt seinen Typ mit sich. ; Prädikate : scheme-value -> boolean number? ; #t gdw Argument ist Zahl boolean? ; #t gdw Argument ist #t oder #f struct? ; #t gdw Argument ist durch define-struct definiert posn? ; #t gdw Argument ist (make-posn v1 v2) circle? ; #t gdw Argument ist (make-circle v1 v2) rectangle? ; #t gdw Argument ist (make-rectangle v1 v2) ; Jede Definition (define-struct (*)) definiert auch ; ein Prädikat ?, welches #t genau für Scheme-Werte der Form ; (make- ...) liefert. ;;; Beispiele (number? 42) (number? (make-posn 1 2)) (number? #t) (boolean? #t) (boolean? 42) (boolean? (make-circle (make-posn 0 0) 5)) (posn? (make-posn 1 2)) (struct? (make-posn 1 2)) ; Neue Art von Definition für einen Datentyp: Varianten ;;; K6.1 Beispiel: Zahlen mit +/- unendlich ; Ein "number*" ist entweder ; 1. number ; oder ; 2. boolean ; Dabei steht #f für -unendlich und #t für +unendlich ; SIGNATUR ; number*-leq : number* number* -> boolean ; ERKLÄRUNG ; kleiner-oder-gleich für number* ; BEISPIEL ; (number*-leq 10 #t) == #t ; (number*-leq 10 10) == #t ; (number*-leq 10 7) == #f ; DEFINITION (define number*-leq (lambda (x y) (or (equal? x y) (equal? x #f) (equal? y #t) (and (number? x) (number? y) (<= x y))))) ; SIGNATUR ; number*-less : number* number* -> boolean ; ERKLÄRUNG ; kleiner-als für number* ; BEISPIEL ; (number*-less 10 #t) == #t ; (number*-less 10 10) == #f ; (number*-less 10 7) == #f ; DEFINITION (define number*-less (lambda (x y) (and (number*-leq x y) (not (equal? x y))))) ; SIGNATUR ; number*-min, number*-max : number* number* -> number* ; ERKLÄRUNG ; Minimum bzw maximum für number* ; BEISPIEL ; (number*-min 10 #t) == 10 ; (number*-max 10 #t) == #t ; (number*-min 10 10) == 10 ; (number*-min 10 7) == 7 ; DEFINITION (define number*-min (lambda (x y) (if (number*-leq x y) x y))) (define number*-max (lambda (x y) (if (number*-leq x y) y x))) ; DEFINITION (Erweiterung von Def K1) ; ::= (or *) ; | (and *) ; Der Wert von (or) ist #f ; Der Wert von (or e) ist der Wert von e. ; Der Wert von (or e1 e2 ... en) wird ermittelt, indem zunächst der ; Wert v1 von e1 ermittelt wird. ; Falls e1 == #t, dann ist das Ergebnis #t. ; Falls e1 == #f, dann ist das Ergebnis der Wert von (or e2 ... en). ; Der Wert von (and) ist #t ; Der Wert von (and e) ist e. ; Der Wert von (and e1 e2 ... en) wird ermittelt, indem zunächst der ; Wert v1 von e1 ermittelt wird. ; Falls e1 == #f, dann ist das Ergebnis #f. ; Falls e1 == #t, dann ist das Ergebnis der Wert von (and e2 ... en). ;;; K6.2 Beispiel: Geometrische Figuren ; Ein "shape" ist ; 1. eine Struktur (make-circle p n) ; mit p : posn und n : number ; oder ; 2. eine Struktur (make-rectangle p1 p2) ; mit p1, p2 : posn ; oder ; 3. eine Struktur (make-line p1 p2) ; mit p1, p2 : posn ; SIGNATUR ; shape-area : shape -> number ; ERKLÄRUNG ; (shape-area s) berechnet den Flächeninhalt von s ; BEISPIELE ; siehe circle-area, rectangle-area, line-area ; DEFINITION (define shape-area (lambda (s) (cond ((circle? s) (circle-area s)) ((rectangle? s) (rectangle-area s)) ((line? s) (line-area s))))) ; DEFINITION (Erweiterung von Def K1) ; ::= (cond ( )*) ; Der Wert von (cond (b1 e1) ... (bn en)) wird ermittelt, indem ; zuerst der Wert v1 von b1 ermittelt wird. ; Falls v1 = #t, dann ist der Wert von e1 das Ergebnis. ; Falls v1 = #f, dann ist der Wert von (cond (b2 e2) ... (bn en)) ; das Ergebnis. ; Der Wert von (cond) ist undefiniert. ;;; Beispiel (shape-area (make-circle (make-posn 0 0) 10)) (cond ((circle? (make-circle (make-posn 0 0) 10)) (circle-area (make-circle (make-posn 0 0) 10))) ((rectangle? (make-circle (make-posn 0 0) 10)) (rectangle-area (make-circle (make-posn 0 0) 10))) ((line? (make-circle (make-posn 0 0) 10)) (line-area (make-circle (make-posn 0 0) 10)))) (cond (#t (circle-area (make-circle (make-posn 0 0) 10))) ((rectangle? (make-circle (make-posn 0 0) 10)) (rectangle-area (make-circle (make-posn 0 0) 10))) ((line? (make-circle (make-posn 0 0) 10)) (line-area (make-circle (make-posn 0 0) 10)))) (circle-area (make-circle (make-posn 0 0) 10)) ((lambda (c) (* pi (square (circle-radius c)))) (make-circle (make-posn 0 0) 10)) (* pi (square (circle-radius (make-circle (make-posn 0 0) 10)))) (* pi (square 10)) (* pi 100) #i314.1592653589793 ; SIGNATUR ; shape-move : shape posn -> shape ; ERKLÄRUNG ; (shape-move s p) erzeugt Kopie von s, die um p verschoben ist ; BEISPIELE ; siehe circle-move, rectangle-move, line-move ; DEFINITION (define shape-move (lambda (s p) (cond ((circle? s) (circle-move s p)) ((rectangle? s) (rectangle-move s p)) ((line? s) (line-move s p)))))