Algorithmen und Programmieren 1

Werbung
Algorithmen und Programmieren 1
Funktionale Programmierung
- Musterlösung zu Übung 3 Dozent: Prof. Dr. G. Rote
Tutoren: J. Fleischer, T. Haimberger,
N. Lehmann, C. Pockrandt, A. Steen
01.11.2011
Ziele dieser Übung
Mit Funktionen höherer Ordnung sicher in Haskell umgehen und die Idee der
Gültigkeitsbereiche verstehen.
In dieser Übung sollte man folgende Konzepte geübt und verstanden haben:
•
Gültigkeitsbereiche (Scope)
•
Listengeneratoren
•
Typdenitionen (type)
•
Funktionen höherer Ordnung
iterate
map
(.)
Aufgabe 13: Kleiner als der Durchschnitt
Schreiben Sie eine Funktion, die berechnet, wie viele Zahlen in einer Liste von
kleiner
Integer-Werten
als der Durchschnittswert sind.
-- Berechnet, wie viele Zahlen in der Liste xs kleiner als der Durchschnittswert sind.
lessThanAVG :: [Integer] -> Int
lessThanAVG xs = length (filter (`ltAvg` xs) xs)
-- Prueft, ob eine Zahl x kleiner als der Durchschnittswert der Liste xs ist.
ltAvg :: Integer -> [Integer] -> Bool
ltAvg x xs = fromIntegral (length xs) * x < sum xs
1
Aufgabe 12: Gültigkeitsbereiche
Geben Sie für jeden eingeführten Namen den Gültigkeitsbereich an.
Aufgabe 12a)
x = 25:: Integer
-->
biggerThanAVG3:: Integer->Integer->Integer->Integer
biggerThanAVG3 x y z =
-->
sum (map (\x -> if fromIntegral x > avg3 x y z then 1
where avg3:: Integer->Integer->Integer->Double
avg3 a b c = fromIntegral (a+b+c) / 3
-->
test1:: Integer
test1 = biggerThanAVG3 3 4 5
-->
fläche:: Float -> Float
fläche x = 2*x^2*pi
-->
public scope
public scope
else 0) [x ,y, z])
private scope(biggerThanAVG3)
public scope
public scope
• x ist global sichtbar. Allerdings NICHT in den Funktionen biggerThanAVG3 und fläche.
• biggerThanAVG3
ist global sichtbar, jeder kann
biggerThanAVG3
aufrufen.
• x im Ausdruck biggerThanAVG3 x y z ist nicht im Ausdruck
(\x -> if fromIntegral x > avg3 x y z then 1 else 0), y und z hingegen schon.
• avg3
biggerThanAVG3
ist nur für
und alle Unterfunktionen von
biggerThanAVG3
sicht-
bar.
• test1
ist global sichtbar, jeder kann
• fläche
test1
ist global sichtbar, jeder kann
aufrufen.
fläche
aufrufen.
Aufgabe 12b)
f x y =
let n = 3 in take n (g y) ++ take n (g x)
where g x = take n xys
where
xys = [x] ++ yxs
yxs = [y] ++ xys
n = 10
• f
--> public scope
--> private scope(f)
--> private scope(g)
--> private scope(g)
--> private scope(f)
ist global sichtbar, jeder kann f aufrufen.
• n im Ausdruck n=3 ist durch die let <expr> in <expr>
take n (g y) ++ take n (g x) sichtbar
• g
ist nur für
f
und alle Unterfunktionen von
g
nur im Ausdruck
sichtbar.
• xys
ist nur für
g
und alle Unterfunktionen von
g
sichtbar.
• xys
ist nur für
g
und alle Unterfunktionen von
g
sichtbar.
• n
im Ausdruck
n=10 ist nur für f und alle Unterfunktionen von f
n aus dem let <expr> in <epxr> dieses n.
sichtbar, allerdings
überschattet das
• x
•
im Ausdruck
Das
y
f x y
im Ausdruck
wird durch das
f x y
ist in ganz
x
im Ausdruck
f
sichtbar.
2
g x
überschattet.
Aufgabe 14: Preisberechnung
Listen der beiden folgenden Datentypen
type Einkaufsliste = [(String, Float)]
type Preisliste
= [(String, Float)]
geben an,
Beispiel
was
gekauft werden soll und
wie viel
(in einer passenden Einheit, z. B. kg), zum
[("Mehl",0.5), ("Butter",0.25)], und andererseits den Preis in Euro pro Einheit
für jeden Artikel.
Aufgabe 14a)
Denieren Sie eine Funktion
preis:: Preisliste -> Einkaufsliste -> (Float,[String])
zur Berechnung des Gesamtpreises aller Artikel einer Einkaufsliste. Die zweite Komponente
des Ergebnisses soll die Liste der Artikelnamen enthalten, die in der Preisliste nicht gefunden
wurden.
type Einkaufsliste = [(String, Float)]
type Preisliste = [(String, Float)]
preis :: Preisliste -> Einkaufsliste -> (Float, [String])
preis preise einkauf = (gesamt, nicht_in_liste)
where
nicht_in_liste = [x | x <- map fst einkauf, not $ elem x bekannte_preise]
bekannte_preise = map fst preise
gesamt = sum [p * p' | (n, p) <- preise, (n', p') <- einkauf, n == n']
-- Testfunktion
testEinkauf = preis [("Butter", 1.09),("Brot", 2.49),("Wurst", 0.99),("Käse", 1.99)]
[("Brot", 2.49),("Butter", 1.09),("Malzbier", 1.0)]
Aufgabe 14b)
Erweitern Sie die Funktion so, dass der Preis für jeden gekauften Artikel der Einkaufsliste auf
Cent gerundet wird.
type Einkaufsliste = [(String, Float)]
type Preisliste = [(String, Float)]
fixedPreis :: Preisliste ->
fixedPreis preise einkauf =
where
nicht_in_liste = [x |
bekannte_preise = map
gesamt = sum [centFix
Einkaufsliste -> (Float, [String])
(gesamt, nicht_in_liste)
x <- map fst einkauf, not $ elem x bekannte_preise]
fst preise
(p * p') | (n, p) <- preise, (n', p') <- einkauf, n == n']
centFix :: Float -> Float
centFix x = fromIntegral (round (x*100))/100
-- Testfunktion
testEinkauf = fixedPreis [("Butter", 1.09),("Brot", 2.49),("Wurst", 0.99),("Käse", 1.99)]
[("Brot", 2.49),("Butter", 1.09),("Malzbier", 1.0)]
3
Aufgabe 15: Funktionsiteration
iter wendet eine Funktion f n-mal hintereinander auf ein Argument
iter 3 f x das Ergebnis f (f (f (x))), das man in der Mathematik
f 3 (x) oder noch genauer f (3) (x) schreibt, damit man es nicht mit der Potenz
Die folgende Funktion
x
an. Zum Beispiel liefert
manchmal als
(f (x))3
verwechselt.
iter n f x
| n==0 = x
| n>0 = f (iter (n-1) f x)
Aufgabe 15a)
Welchen Typ hat
iter?
-- Theoretisch könnte der Typ von iter wie folgt aussehen:
iter :: (Num t, Ord t) => t -> (a -> a) -> a -> a
-- Da die Abbruchbedingung aber n == 0 ist (statt z.B. n < 0)
-- sollte man Bruchzahlen ausschlieÿen.
iter :: Integral t => t -> (a -> a) -> a -> a
Aufgabe 15b)
Geben Sie eine alternative Denition als Funktion
iter n f
ohne den Parameter
x.
-- Eine alternative Definition ohne den Parameter x.
iter2 :: Int -> (a -> a) -> a -> a
iter2 n f
| n == 0 = id -- Identität
| n > 0 = f.(iter (n-1) f) -- Komposition
Aufgabe 15c)
Lösen Sie Aufgabe 4b (Zinseszinsen) mit Hilfe der Funktion
iter und der Lösung von Aufgabe
4a. (Achten Sie auf die Reihenfolge der Argumente.)
-- Die gegebene Funktion zur Berechnung der Zinsen.
zinsen :: Double -> Double -> Double
zinsen kapital zinsfuss = kapital * zinsfuss * 0.01
-- Diese Funktion berechnet den Zinseszins nach einer Zeitperiode.
endwert :: Double -> Double -> Double
endwert kapital zinsfuss = kapital + (zinsen kapital zinsfuss)
-- Diese Funktion berechnet den Zinseszins nach zwei Zeitperioden.
endwert2 :: Double -> Double -> Double
endwert2 kapital zinsfuss = iter 2 (`endwert` zinsfuss) kapital
-- Diese Funktion berechnet den Zinseszins nach k Zeitperioden.
endwertN :: Double -> Double -> Int -> Double
endwertN kapital zinsfuss k = iter k (`endwert` zinsfuss) kapital
4
Aufgabe 16: Iterierter Logarithmus
Die Funktion
Zahl
y,
logBase a x = loga x berechnet den Logarithmus von x zur Basis a; das ist die
ay = x ist.
für die
Aufgabe 16a)
Bestimmen Sie die kleinste Zahl
x,
für die
logBase 2 x >= 5
ist.
-- Findet die kleinste natuerliche Zahl, fuer die logBase b x >= y ist.
-- Idee: logBase b x >= y gilt genau dann, wenn x >= b**y ist.
minLog :: Double -> Double -> Int
minLog b y = ceiling (b**y)
-- Es folgt eine alternative Definitionen mit Listengeneratoren.
-- Die Auswertung dauert wesentlich länger.
minLog' :: Double -> Double -> Int
minLog' b y = (truncate.head) kandidaten
where kandidaten = [x | x <- [1..], logBase b x >= y]
Aufgabe 16b)
Bestimmen Sie die kleinste Zahl
x,
für die
iter 3 (logBase 2) x >= 2
ist.
-- Findet die kleinste natuerliche Zahl, fuer die
-- iter n (logBase b) x >= y ist.
-- Idee: logBase b (logBase b (logBase b x)) >= y gilt genau dann,
-- wenn x >= b**b**b**y ist.
minIter :: Int -> Double -> Double -> Int
minIter n b y = ceiling (iter n (b**) y)
-- Es folgt eine alternative Definitionen mit Listengeneratoren.
-- Die Auswertung dauert wesentlich länger.
minIter' :: Int -> Double -> Double -> Int
minIter' n b y = (truncate.head) kandidaten
where kandidaten = [x | x <- [1..], iter n (logBase b) x >= y]
5
Aufgabe 17: Potenzieren, Summe und Produkt
Das Potenzieren mit einer natürlich Zahl als Exponent kann man als iteriertes Multiplizieren
denieren:
xn := x · x · x · · · x
mit
n
Faktoren:
potenz x n = iter n (x*) 1
Aufgabe 17a)
·x
··
turm x k = x ↑ k :=
rechten Seite x insgesamt k -mal
Die Turmfunktion
Turm auf der
x
xx
ist eine geschachtelte Potenz, bei der in dem
vorkommt. (Potenzieren ist rechtsassoziativ!)
Denieren Sie diese Funktion unter Verwendung von
potenz
und
iter.
-- Berechnet die Potenz x^n.
potenz :: Num a => a -> Integer -> a
potenz x n = iter n (x*) 1
-- Die in der Aufgabenstellung beschriebene Turmfunktion.
turm :: Integer -> Integer -> Integer
turm x k = iter (k-1) (potenz x) x
Aufgabe17b)
Die
Multiplikation
chende Funktion
kann als iterierte Addition aufgefasst werden. Schreiben Sie eine entspre-
mal a b,
die analog zur Funktion
potenz
das Produkt als iterierte Summe
deniert.
-- Definiert das Produkt als iterierte Summe.
mal :: Num a => Integer -> a -> a
mal x y = iter x (y+) 0
Aufgabe 17c)
Welche Funktion muss man iterieren, damit man die
Summenfunktion
erhält? Schreiben Sie eine entsprechende Funktionsdenition für
plus.
plus a b = a + b
-- Um die Summenfunktion zu erhalten, muss man die Nachfolgerfunktion (+1) iterieren.
plus :: Num a => Integer -> a -> a
plus a b = iter a (+1) b
6
Aufgabe 18: Funktionsiteration
Aufgabe 18a)
g = iter 23 deniert. Wie können Sie das Argument 23 aus der
g herausnden? Schreiben Sie eine Funktion entdecke, die für alle n ≥ 0 die folgende
Jemand hat die Funktion
Funktion
Beziehung erfüllt:
entdecke (iter n) == n,
-- Die Beispielfunktion aus der Aufgabenstellung.
g :: (a -> a) -> a -> a
g = iter 23
-- Es soll gelten: entdecke (iter n) == n.
entdecke :: (Num a, Num b) => ((a -> a) -> b -> c) -> c
entdecke f = f (1+) 0
Aufgabe 18b)
Addition: Schreiben Sie eine Funktion
sumiter
mit der Eigenschaft
sumiter (iter a) (iter b) == iter (a+b),
Verwenden Sie nicht einfach
entdecke
und
+,
für alle
a, b ≥ 0.
sondern suchen Sie eine direktere Denition.
-- Es soll gelten: sumiter (iter n) (iter m) == iter (n+m)
sumiter :: (a -> b -> c) -> (a -> c -> d) -> a -> b -> d
sumiter f g h = (g h).(f h)
-- Alternativ: sumiter f g h x = g h (f h x)
Aufgabe 18c)
Multiplikation: Schreiben Sie eine analoge Funktion
proditer
für das Produkt von
-- Es soll gelten: proditer (iter n) (iter m) == iter (n*m)
-- Schrittweise Vereinfachung der Definition:
---> proditer f g h x = f (g h) x
---> proditer f g h = f (g h)
---> proditer f g h = (f.g) h
---> proditer f g = f.g
proditer :: (b -> c) -> (a -> b) -> a -> c
proditer = (.)
7
a
und
b.
Herunterladen