; Muesterloesung Aufgabenblatt 11
; P1 [[WiSe]] 04/05
; Oezguer Oezcep
;;; Aufgabe 1 (Abstrakter Datentyp)
;;; ------------------------------
;;; Umrechnungskurs
(define [[EURO2DOLLAR]] 1.32)
(define [[EURO2PFUND]] 0.70)
;;; (a)
(define (neuerGeldbetrag wert waehrung)
(list wert waehrung))
;;; Test
; > (neuerGeldbetrag 2 'Euro)
; (2 euro)
;;;(b)
(define (wert[[VonBetrag]] betrag)
(car betrag))
;(define (waehrung[[VonBetrag]] betrag)
; (car (cdr betrag)))
; bzw. kuerzer
(define (waehrung[[VonBetrag]] betrag)
(cadr betrag))
;;; Test
; > (wert[[VonBetrag]] (neuerGeldbetrag 2 'Euro))
; 2
; > (waehrung[[VonBetrag]] (neuerGeldbetrag 2 'Euro))
; euro
;;;(c)
(define (nachEuro betrag)
(case (waehrung[[VonBetrag]] betrag)
; ist schon Euro => keine Aenderung
((euro) betrag)
; Konvertierung von Dollar
((dollar)
(neuerGeldbetrag (/ (wert[[VonBetrag]] betrag) [[EURO2DOLLAR]]) 'Euro))
; Konvertierung von Pfund
((pounds)
(neuerGeldbetrag (/ (wert[[VonBetrag]] betrag) [[EURO2PFUND]]) 'Euro))
; falsche Waehrung => false
(else #f)))
(define (vonEuro betrag waehrung)
(cond
; falsche Quellwaehrung => false
((not (eq? (waehrung[[VonBetrag]] betrag) 'euro)) #f)
; Euro nach Euro
((eq? waehrung 'euro) betrag)
; Euro nach Dollar
((eq? waehrung 'dollar)
(neuerGeldbetrag (* (wert[[VonBetrag]] betrag) [[EURO2DOLLAR]]) 'Dollar))
; Euro nach Pfund
((eq? waehrung 'pounds)
(neuerGeldbetrag (* (wert[[VonBetrag]] betrag) [[EURO2PFUND]]) 'Pounds))
; falsche Zielwaehrung => false
(else #f)))
;;; Test
; Wir testen, dass Hin- und Rueckkonvertierung wieder den originalen Betrag
; ergibt
; > (nachEuro (vonEuro (neuerGeldbetrag 2 'Euro) 'Euro))
; (2 euro)
; > (nachEuro (vonEuro (neuerGeldbetrag 2 'Euro) 'Dollar))
; (2.0 euro)
; > (nachEuro (vonEuro (neuerGeldbetrag 2 'Euro) 'Pounds))
; (2.0 euro)
;;; d)
;;; Vorbedingung: die Waehrungen von betrag1 und betrag2 sind gleich
(define (addiere[[WaehrungsgleicheBetraege]] betrag1 betrag2)
(let* (
(wert1 (wert[[VonBetrag]] betrag1))
(wert2 (wert[[VonBetrag]] betrag2))
(waehrung (waehrung[[VonBetrag]] betrag1))
(summe (+ wert1 wert2))
)
(neuerGeldbetrag summe waehrung)))
;;; Test
; > (addiere[[WaehrungsgleicheBetraege]] (neuerGeldbetrag 2 'Euro) (neuerGeldbetrag 4 'Euro))
; (6 euro)
;;; e)
(define (addiere betrag1 betrag2)
(let* (
; Konvertiere Betraege nach Euro und ...
(neuer[[GeldbetragInEuro1]] (nachEuro betrag1))
(neuer[[GeldbetragInEuro2]] (nachEuro betrag2))
)
; ... addiere mit addiere[[WaehrungsgleicheBetraege]]
(addiere[[WaehrungsgleicheBetraege]] neuer[[GeldbetragInEuro1]] neuer[[GeldbetragInEuro2]])))
;;; Test
; > (addiere (neuerGeldbetrag 2 'Euro) (neuerGeldbetrag 2 'Euro))
; (4 euro)
; > (addiere (neuerGeldbetrag 2 'Euro) (neuerGeldbetrag 2 'Dollar))
; (3.515151515151515 euro)
; > (addiere (neuerGeldbetrag 2 'Dollar) (neuerGeldbetrag 2 'Euro))
; (3.515151515151515 euro)
; > (addiere (neuerGeldbetrag 2 'Dollar) (neuerGeldbetrag 2 'Dollar))
; (3.0303030303030303 euro)
;;; Aufgabe 2 (Teilstuecke einer Liste)
;;; -----------------------------------
;;; a)
; Zunaechst eine Loesung ohne Fehlerbehandlung. Die Idee: Falls die Tiefe noch
; groesser ist als 0, besteht die Loesung aus dem Kopf und den ersten n-1 Elementen
; des Schwanzes:
(define (take n liste)
(cond
((= n 0)
'())
(else
(cons
(car liste)
(take (- n 1) (cdr liste))))))
; Zwei Reaktionen bei zu hohem n koennen als sinnvoll angesehen werden:
; 1) Ausgabe eines Fehlers
; 2) Rueckgabe der gesamten Liste
; Die Loeung fuer Variante 1) laesst sich z.B. durch eine Wrapper-
; Funktion realisieren, welche take nur aufruft, falls n <= (length liste):
(define (w_take n liste)
(if (<= n (length liste))
(take n liste)
(error "n ist groesser als die Listenlaenge")))
;;; Test:
;> (w_take 1 '(1 2 3))
;(1)
;> (w_take 2 '(1 2 3))
;(1 2)
;> (w_take 4 '(1 2 3))
; n ist groesser als die Listenlaenge
;> (w_take 4 '(1 2 3))
; Die Loesung fuer Variante 2) erreicht man, indem nicht nur das Erreichen von
; n=0 zum Rekursionsabbruch fuehrt, sondern auch (null? list) :
(define (take n liste)
(cond
((= n 0)
'())
((null? liste) ; <--
'()) ; <--
(else
(cons
(car liste)
(take (- n 1) (cdr liste))))))
;;; Test:
;> (take 4 '(1 2 3))
;(1 2 3)
;;;(b)
; Zunaechst wieder die Loesung ohne Fehlerbehandlung.
(define (drop n liste)
(cond
((= n 0)
liste)
(else
(drop (- n 1) (cdr liste)))))
; Abgefangen muss hier der Fall werden, dass mehr Elemente abgeschnitten
; werden sollen als die Liste Elemente hat. Analog sind wieder 2 Reaktionen
; moeglich:
; 1) Ausgabe eines Fehlers
; 2) Rueckgabe der leeren Liste
; Die Loesung fuer Variante 1) analog zu a):
(define (w_drop n liste)
(if (<= n (length liste))
(drop n liste)
(error "n ist zu gross")))
;;;; Test:
;> (w_drop 1 '(1 2 3))
;(2 3)
;> (w_drop 0 '(1 2 3))
;(1 2 3)
;> (w_drop 2 '(1 2 3))
;(3)
;> (w_drop 4 '(1 2 3))
; n ist zu gross
; Und auch bei 2) koennen wir uns an a) orientieren: Falls (null? liste) ist,
; gib die leere Liste zurueck.
(define (drop n liste)
(cond
((= n 0)
liste)
((null? liste) ; <--
'()) ; <--
(else
(drop (- n 1) (cdr liste)))))
;;;Test:
;> (drop 4 '(1 2 3))
;()
;;; c)
; Anders formuliert: (subseq start stop liste) bewirkt, dass von den ersten
; 'stop' Elementen von 'liste' die ersten 'start' Elemente abgeschnitten werden:
(define (subseq start stop liste)
(drop
start
(take (+ stop 1) liste)))
; Das (+ stop 1) ergibt sich dabei aus der Tatsache, dass take die ersten n
; Elemente der Liste bestimmt, also z.b. 4 Elemente, welche aber fuer subseq
; mit den werten 0-3 nummeriert sind. Aus eben diesem Grund muss auch start
; nicht veraendert werden, denn dadurch dass bei 0 angefangen wird zu zaehlen
; enthaelt start schon genau die Anzahl an Elementen, die entfernt werden muessen
;;; Test
;> (subseq 0 0 '(1 2 3))
;(1)
;> (subseq 0 1 '(1 2 3))
;(1 2)
;> (subseq 0 2 '(1 2 3))
;(1 2 3)
;> (subseq 0 3 '(1 2 3))
;(1 2 3)
;> (subseq 1 2 '(1 2 3))
;(2 3)
;> (subseq 3 0 '(1 2 3))
;()
;;; Aufgabe 3 (Gute Vorsaetze)
;;;---------------------------
;;; Hilfsfunktionen von Dreschler-Fischer's tools.scm
;;;; =========================================================
;;;; random numbers
;;;; =========================================================
(define *last-ran* 1) ; the previous random number
(define (random-real)
;;; pick a random real number between 0 and 1.0
(let* ((a (add1 (expt 2 7)))
(b 1)
(T (sub1 (expt 2 35)))
(next-ran (remainder
(+ (* a *last-ran*)
b)
T)))
(set! *last-ran* next-ran)
(/ next-ran T)))
(define (random n)
;;; pick a random integer between 0 and n-1
(floor (* n (random-real))))
(define (random-elt choices)
;;; Choose an element from a list at random
(list-ref choices (random (length choices))))
;;; ----------------------------------------------
;;; Die Hilfsfunktion one-of (Skript S. 107) in etwas variierter Form
;;; Das zufaellig aus der Liste set gewhlte Element wird nur in dem Fall,
;;; dass es keine Liste ist, in eine Liste eingebettet.
(define (one-of set)
(let ((element (random-elt set)))
(if (list? element) element (list element))))
;;; a)
;Es werden zur Loesung der Aufgabe nur solche Vorsaetze betrachtet, die sich in der
; Form <Skalar> <Verbalphrase> wiedergeben lassen.
;Da nach "guten" Vorsaetzen gefragt ist, ist die Kombination der Skalare mit den
;Verbalphrasen zu beachten; z.B. ist (weniger rauchen) ein guter Vorsatz, hingegen
;(mehr rauchen) nicht.
;
;In der Grammatik muessen folglich "positive" und "negative" Verbalphrasen sowie
;+Skalare ("mehr", haeufiger") und -Sklarae ("weniger", "seltener") unterschieden
;werden. Ein guter Vorsatz sollte einer sein, der mehr an positiven Taten oder
;weniger an negativen Taten verlangt.
;
;
;
;Grammatik
;
;(1) <+Skalar> ::= mehr | fleissiger | haeufiger
;(2) <-Skalar> ::= weniger | seltener
;(3) <positiveVerbalphrase> ::= sparen | lernen | lesen | Sport treiben
;(4) <negativeVerbalphrase>::= trinken | Auto fahren | rauchen
;(5) <guterVorsatz> ::= <+Skalar><positiveVerbalphrase>
;(6) <guterVorsatz> ::= <-Skalar><negativeVerbalphrase>
;;; b)
; Regeln der (einfachen) Grammatik als Scheme-Code
(define (guterVorsatz)
; waehlt zufaellig einen der beiden Faelle ( (5) oder (6) )
; fuer guete Vorsaetze aus
(random-elt (list
(append (-Skalar) (negativeVerbalphrase))
(append (+Skalar) (positiveVerbalphrase)))))
(define (negativeVerbalphrase)
(one-of (list 'trinken (list 'Auto 'fahren) 'rauchen)))
(define (positiveVerbalphrase)
(one-of (list 'sparen 'lernen (list 'Sport 'treiben) 'lesen)))
(define (+Skalar)
(one-of '(mehr fleissiger haeufiger)))
(define (-Skalar)
(one-of '(weniger seltener)))
;;;; Test
;> (guterVorsatz)
;(haeufiger lesen)
;> (guterVorsatz)
;(fleissiger lernen)
;> (guterVorsatz)
;(weniger auto fahren)
;> (guterVorsatz)
;(seltener rauchen)
;> (guterVorsatz)
;(weniger auto fahren)
;> (guterVorsatz)
;(fleissiger lesen)
;> (guterVorsatz)
;(haeufiger lesen)
;> (guterVorsatz)
;(fleissiger sport treiben)
;> (guterVorsatz)
;(weniger trinken)
;> (guterVorsatz)
;(weniger auto fahren)
;> (guterVorsatz)
;(weniger trinken)
;> (guterVorsatz)
;(mehr sparen)
;> (guterVorsatz)
;(mehr sport treiben)
;> (guterVorsatz)
;(mehr sport treiben)
;> (guterVorsatz)
;(mehr sport treiben)
;> (guterVorsatz)
;(weniger auto fahren)
;> (guterVorsatz)
;(haeufiger lernen)
;> (guterVorsatz)
;(seltener trinken)
;> (guterVorsatz)
;(seltener rauchen)
;> (guterVorsatz)
;(weniger rauchen)