ProInformatik, Musterlösung Tag 18 und 19 Funktionen höherer

Werbung
ProInformatik, Musterlösung
Tag 18 und 19
Funktionen höherer Ordnung
Aufgabe 1
length :: [a] -> Int
length xs = (sum . map (\x -> 1)) xs
Aufgabe 2
allGreaterZero :: (Num a, Ord a) => [a] -> Bool
allGreaterZero xs = (((==) 0) .length . filter (\x -> (x < 1))) xs
Aufgabe 3
iter :: Int -> (a -> a) -> a -> a
iter 0 _ a = a
iter n f a = f (iter (n - 1) f a)
Aufgabe 4
sumOfSquares :: (Num a) => [a] -> a
sumOfSquares xs = (foldr (+) 0 . map (^ 2)) xs
Typherleitung, Typüberprüfung
Aufgabe 5
Nein, auf Grund des Kommas in der Liste ("[x, Double]").
Aufgabe 6
(i) - (ii)
instance (Ord a, Ord b) => Ord (a,b) where
(<=) (a,b) (c,d) = (a < c) || (a == c) && (b <= d)
instance Ord
(<=)
(<=)
(<=)
b => Ord [b] where
[] _ = True
_ [] = False
(a:as) (b:bs) = (a < b) || (a == b) && as <= bs
(iii)
a)
b)
c)
d)
e)
Typkorrekt, Wert: True.
Typkorrekt, Wert: False.
Nicht typkorrekt, da [[Int]] mit einer [Int] verglichen wird.
Typkorrekt, Wert: True
Typkorrekt, Wert: True, gemeint war (1,2)<(2,1)
Aufgabe 7
Nicht vollständig, da Herleitungen fehlen
a)
map :: (a -> b) -> [a] -> [b]
zip :: [a] -> [b] -> [(a, b)]
[[a]] -> [[b] -> [(a, b)]]
b)
uncurry :: (a -> b -> c) -> (a, b) -> c
id :: a -> a
((b -> b1 -> c, b), b1) -> c
c)
uncurry :: (a -> b -> c) -> (a, b) -> c
zip :: [a] -> [b] -> [(a, b)]
([a], [b]) -> [(a, b)]
d)
curry :: ((a, b) -> c) -> a -> b -> c
Nicht korrekt, weil die Signatur von curry nicht zu ((a, b) -> c) (curry) passt
Aufgabe 8
class Visible t
where
toString :: t -> String
size :: t -> Int
instance (Num a) => Visible [a] -- "instance Visible [Int]" geht nicht
where
toString xs = show xs
size xs = length xs
Textaufgabe
Aufgabe 9
type Name = String; type Note = Float; type Arbeit = (Name, Note); type
Ergebnisse = [Arbeit]
besteSchüler :: Ergebnisse -> [Name]
besteSchüler erg = [ name | (name,note) <- erg, note == 1.0 ]
eintrag :: Ergebnisse -> Arbeit -> Ergebnisse
eintrag erg a = a:erg
zeugnisNote :: Ergebnisse -> Name -> Note
zeugnisNote erg name = mw [ no | (na,no) <- erg, name == na ]
mw :: [Float] -> Float
mw [] = error "Der Mittelwert kann nicht von einer leeren Liste berechnet
werden."
mw l = sum l / fromIntegral (length l)
mittelwert :: Ergebnisse -> Note
mittelwert erg = mw [ note | (name,note) <- erg ]
Aufgabe 10
Die Aufgabe ist nicht ganz vollständig, zu einer Ausleihe gehören auch Angaben über die
Personen, die ausleihen.
type
type
type
type
Titel = String
Anzahl = Int
Artikel = (Titel, Anzahl)
Bestand = [Artikel]
type Ausleiher = String
type Ausleih = (Ausleiher, Titel)
type Ausleihe = [Ausleih]
lJustify :: Int -> Char -> String -> String
lJustify n c s
| Prelude.length s < n = lJustify n c (s ++ [c])
| otherwise = s
showArtikel :: Artikel -> String
showArtikel (t, a) = lJustify 25 ' ' t ++ show a
showAllArtikel :: Bestand -> String
showAllArtikel [] = ""
showAllArtikel (x:xs) = showArtikel x ++ "\n" ++ showAllArtikel
xs
showBestand :: Bestand -> IO ()
showBestand = putStr . ("Bestand:\n" ++) . showAllArtikel
showAusleih :: Ausleih -> String
showAusleih (n, t) = lJustify 25 ' ' n ++ t
showAllAusleihe :: Ausleihe -> String
showAllAusleihe [] = ""
showAllAusleihe (x:xs) = showAusleih x ++ "\n" ++ showAllAusleihe
xs
showAusleihe :: Ausleihe -> IO ()
showAusleihe = putStr . ("Ausleihe:\n" ++) . showAllAusleihe
ZF-Notation
Aufgabe 11
cantor :: Int -> [(Int,Int)]
cantor 0 = [(0,0)]
cantor k
| not (even k) = cantor (k-1) ++ zip (reverse([i|i<-[0..k]])) [i|i<-[0..k]]
| otherwise = cantor (k-1) ++ zip [i|i<-[0..k]] (reverse([i|i<-[0..k]]))
cantor gibt die Liste aller Diagonalen von 0 . . . k. Um die Aufgabe zu lösen muss man von dieser
Liste nur noch die ersten k Elemente nehmen.
Aufgabe 12
a) Eine rekursive Definition für tud (teste und verdopple)
tud :: Num t => (t->Bool) -> [t] -> [t]
tud p [] = []
tud p (a:l)
| p a
= (2 * a) : tud p l
| otherwise =
tud p l
{- eine Beispielrechnung:
Main> tud istGerade [1..10]
[4,8,12,16,20] :: [Int]
b) Eine nichtrekursive Definition für tud unter Verwendung von map und filter
tud' :: Num t => (t->Bool) -> [t] -> [t]
tud' p l = map (2*) (filter p l)
c) Eine Definition für tud unter Verwendung der ZF-Listennotation
tud'' :: Num t => (t->Bool) -> [t] -> [t]
tud'' p l = [2 * a | a <- l, p a ]
Aufgabe 13
zensur :: String -> String -> String
zensur w s = concatWith (check (words s) w) " "
where
concatWith :: [[a]] -> [a] -> [a]
concatWith [] _ = []
concatWith [e] _ = e
concatWith (e1:e2:xs) w = concatWith ((e1 ++ w ++ e2):xs) w
check :: [String] -> String -> [String]
check [] _ = []
check (x:xs) w
| w == x = (replicate (length x) 'x'): check xs w
| otherwise = x:check xs w
Lambda-Kalkül
Aufgabe 14
a) (λp. (λq. (p) q) (λx.x) λa. λb. a) λk.k
Ist korrekt, Freie Variable: keine
Reduktion:
(λp. (λq. (p) q) (λx.x) λa. λb. a) λk.k -> (λq. (λk.k) q) (λx.x) λa. λb. a
-> (λk.k) (λx.x) λa. λb. a -> (λx.x) λa. λb. A -> λa. λb. a
b) (λx. (λy. (λz. (x) λx. (x) y))) y x z
Nicht korrekt, weil "(...) x y z" und es gilt <Application> := (<λ-Ausdruck>) <λ-Ausdruck>
c) (((λf. λg. λx. ((f) g) x) λs.(s)s) λa. λb.b) λx. λy.x
Ist korrekt, Freie Variable: keine
Reduktion:
(((λf. λg. λx. ((f) g) x) λs.(s)s) λa. λb.b) λx. λy.x ->
(( λg. λx. ((λs.(s)s) g) x) λa. λb.b) λx. λy.x ->
( λx. ((λs.(s)s) λa. λb.b) x) λx. λy.x ->
((λs.(s)s) λa. λb.b) λx. λy.x ->
((λa. λb.b)λa. λb.b) λx. λy.x ->
(λb.b) λx. λy.x ->
λx. λy.x
Vollständige Induktion
Aufgabe 15
Sei M eine Menge von natürlichen Zahlen mit |M|=n Є N. Zeigen Sie, dass für alle natürlichen
Zahlen n gilt:
|P(M)|=2n, wobei P(M) die Potenzmenge von M ist.
Beweis durch vollst. Induktion über n.
Induktionsanfang:
Sei n=0, dann ist P(M) = {{}} -> |P(M)| = 1
2 ^ n= 2^0=1
Induktionsschritt:
Induktionsvoraussetzung:
Sei |M|=n mit n, bel. und fest aus N.
Dann gilt: |P(M)| = 2^n
Induktionsbehauptung:
Für |M|=n+1 ist |P(M)| = 2^(n+1)
Beweis:
Sei |M|=n. Wird ein weiteres Element x in M eingefügt mit |M U {x}|=n+1 dann gilt für die
Potenzmenge:
| P(M U {x}) |= |P (M) U {x U a|a Є P(M)}| =|P (M)| +| {x U A|AЄP(M)}| = 2^n + 2^n=2^(n+1)
Aufgabe 16
Zeige, dass für alle Listen xs der Länge n, f.a. n Є N gilt:
f p xs = map (2*) (filter p xs)
Induktionsanfang:
f p [] = []
(f.1)
map (2*) (filter p []) = []
(filter.1, map.1)
Induktionsschritt:
Sei xs Liste mit bel. fester Länge n.
Induktionsvoraussetzung: (I.V.) es gilt f p xs = map (2*) (filter p xs)
Induktionsbehauptung: f p (x:xs) = map (2*) (filter p (x:xs))
1.Fall (p x ergibt True)
f p (x:xs) = (2 * x) : f p xs (f.2)
= (2 * x) : map (2*) (filter p xs) (I.V.)
map (2*) (filter p (x:xs))
= map (2 *) (x : filter p xs)
(filter.2)
= (2 * x) : map (2 *) (filter p xs) (map.2)
2.Fall (p x ergibt False)
f p (x:xs) = f p xs (f.2)
= map (2*) (filter p xs) (I.V.)
map (2 *) (filter p (x:xs))
= map (2 *) (filter p xs)
(filter.2)
Aufgabe 17
Zeige, dass für alle Bäume b vom Typ Baum a gilt:
occurs b a = length (filter (==a) (collapse b))
Induktionsanfang:
doppelt f [] = []
doppelt' f [] = map (f.f) []
= []
(doppelt.1)
(doppelt')
(map.1)
Induktionsschritt:
Zeige doppelt f (a:l) = doppelt' f (a:l) unter der
Induktionsannahme (I.A.), dass doppelt f l = doppelt' f l
gilt.
doppelt f (a:l) = (f(f a)) : doppelt f l
= (f.f) a : doppelt f l
= (f.f) a : doppelt' f l
doppelt' f (a:l) = map (f.f) (a:l)
= (f.f) a : map (f.f) l
= (f.f) a : doppelt' f l
(doppelt.2)
(.)
(I.A.)
(doppelt')
(map.2)
(doppelt' rückwärts)
Laufzeitanalyse
Aufgabe 19
In der Klausur müssen Sie bitte begründen, warum Sie worauf kommen. Hier nur in Kürze die
Rechnung:
-- a)
Tins'(0) = 1
1. Guard:
Tins'(n) = 1 + (n - 1) + (n - 1) + n + n + 1
-- für reverse, und anschließende (++)
-> O(n) -- da nach einem rekursiven Aufruf erstes Pattern greift.
2. Guard:
Tins'(n) = Tins'(n - 1) + 1 -> O(n)
Tins(0) = 1
Tins(n) = n + Oins'(n) -> O(n)
-- b)
Hier müssen jetzt mehrere Fälle betrachtet werden:
1. Fall, die Knoten sind gleichmäßig verteilt, der Baum ist balanciert:
Tcol(0) = 1
Tcol (n) = Tcol((n - 1) / 2) +(( n - 1) / 2) + 1
= 2* Tcol((n - 1) / 2) +(( n - 1) / 2) -- es wird die Summe gebildet von
n/2+n/4+n/8+...+1=c*n
-> O(n)
2. Fall, Baum ist entartet zur linken Seite:
Tcol(0) = 1
Tcol (n) = Tcol(n - 1) +( n - 1) +1
= Summe von 1 bis n
-> O(n^2)
3. Fall, Baum ist entartet zur rechten Seite:
Tcol(0) = 1
Tcol (n) = Tcol(n - 1) +1 +1
= c*n
-> O(n)
-- c)
Gleicher Analyseweg wie in b)
-- d)
tiefe :: (Eq a) => a -> Baum a -> Int
tiefe s b = find s b 0
where
find :: (Eq a) => a -> Baum a -> Int -> Int
find _ Leer _ = -1
find s (B l e r) a
| s == e = a
| otherwise = max (find s l (a + 1)) (find s r (a + 1))
1. Fall: Element s ist die Wurzel
1. Guard -> O(1)
2. Fall: Worst case:
Element bestimmt die Höhe des Baumes und alle Zweige müssen überprüft werden. Der
Einfachheit halber wird angenommen, dass der Baum im Durchschnitt ausgeglichen ist, dass
also jeder Teilbaum die gleiche Anzahl an Knoten enthält:
Ttie(0) = 1
Ttie (n) = Ttie ((n - 1) / 2) + Ttie ((n - 1) / 2) + 1
-> O(n)
3. Fall: Element befindet sich im Durchschnitt zwischen Wurzel und dem höchsten Blatt, dann
beträgt die Laufzeit im Schnitt die Hälfte von Fall 2, also O(n/2) -> O(n).
Algebraische Datentypen
Aufgabe 20
a)
data MischFarbe = F Farbe | MF MischFarbe MischFarbe
b)
colour
colour
colour
colour
:: Farbe -> String
Rot = "R"
Gelb ="G"
Blau ="B"
instance Show MischFarbe
where
show (F f) = colour f
show (MF mf f) = show mf ++ colour f
Aufgabe 21
a)
data Baum a = Leer | B (Baum a) a Int (Baum a)
deriving (Eq, Ord, Show)
-- b)
baum :: Baum Int
baum = (B (B (B (B (B Leer 1 4 Leer) 2 3 Leer) 3 2 Leer) 4 1 Leer) 5 0 Leer)
-- c)
inorder :: Baum a -> [(a, Int)]
inorder Leer = []
inorder (B l x t r) = inorder l ++ [(x, t)] ++ inorder r
-- d)
insert :: (Ord a) => Baum a -> a -> Baum a
insert Leer e = (B Leer e 0 Leer)
insert (B l x t r) e
| l == Leer && e <= x = (B (B Leer e (t + 1) Leer) x t r)
| e <= x = (B (insert l e) x t r)
| r == Leer && e > x = (B l x t (B Leer e (t + 1) Leer))
| e > x = (B l x t (insert r e))
Sortieralgorithmen
Aufgabe 22
quickSort :: (Ord a) => [a] -> [a]
quickSort [] = []
quickSort (x:xs) = quickSort [y | y <- xs, y > x] ++ [x] ++ quickSort [z | z <- xs, z < x]
insertionSort :: (Ord a) => [a] -> [a]
insertionSort [] = []
insertionSort (x:xs) = insert (insertionSort xs) x
where
insert :: (Ord a) => [a] -> a -> [a]
insert [] e = [e]
insert (x:xs) e
| e == x = x:xs
| e > x = e:x:xs
| otherwise = x:insert xs e
Aufgabe 23
ordTrip :: (Ord a) => [a] -> [a]
ordTrip [] = []
ordTrip _ = []
ordTrip (x1:x2:x3:xs) = quickSort [x1, x2, x3] ++ ordTrip xs
where
quickSort :: (Ord a) => [a] -> [a]
quickSort [] = []
quickSort (x:xs) = quickSort [y | y <- xs, y <= x] ++ [x] ++ quickSort [z | z <- xs, z > x]
Aufgabe 24
sortB :: (Ord a) => [a] -> [a]
sortB [] = []
sortB (x:xs) = inorder (sort (insert Leer x) xs)
where
sort :: (Ord a) => Baum a -> [a] -> Baum a
sort b [] = b
sort b (x:xs) = sort (insert b x) xs
inorder :: Baum a -> [a]
inorder Leer = []
inorder (B l x t r) = inorder l ++ [x] ++ inorder r
Aufgabe 25
Implementieren Sie den ADT Stack (Stapel) in Haskell mit Hilfe eines Moduls.
Der Stack s ist definiert durch die Funktionen:
push(e)
-- fügt ein Element e in den Stack
pop()
-- gibt das zuletzt in s eingefügte Element zurück und löscht es
top()
-- gibt das zuletzt in s eingefügte Element zurück
isEmpty()
-- gibt an, ob der Stack leer ist
Ihre Implementierung kann eine Liste benutzen sollte aber effizient sein, d.h. alle Funktionen
sollten Laufzeit O(1) haben.
module Stack (Stack, push, pop, top, isEmpty)
where
data Stack a = L | S a (Stack s)
push x Leer = S x Leer
push x stack = S x stack
pop Leer = error “Stack ist leer”
pop (S x rest) = (x,rest)
top Leer = error “Stack ist leer”
top (S x rest) = x
isEmpty Leer = True
isEmpty l = False
Herunterladen