Paradigmen der Programmierung

Werbung
Dr. A. Raschke
Prof. Dr. H. Partsch
Aufgabe 5
Paradigmen der Programmierung
SS 11 Prüfungsklausur
25.07.2011
(6+9 = 15 Punkte)
a) Bestimmen Sie jeweils den Typ der folgenden Haskell-Ausdrücke:
(’1’, ’2’:"3", 4 < 5)
::
(Char, String, Bool)
[(last, tail), (head, take 5)] ::
[ ([a] -> a, [b] -> [b]) ]
[map (const True), map not]
[ [Bool] -> [Bool] ]
::
b) Gegeben seien die folgenden Funktionsdefinitionen. Bestimmen Sie jeweils den
allgemeinsten Typ der Funktionen. Denken Sie auch an eventuelle Klasseneinschränkungen.
Hinweis: Auftretende Zahlenkonstanten können Sie als Int interpretieren.
f
f x y z
elemIndex
elemIndex x xs
g
::
=
::
head (drop x y) <= z
Eq a => a -> [a] -> Maybe Int
=
case [i | (y,i) <- zip xs [0..], y == x] of
[]
-> Nothing
(i:_) -> Just i
::
(Ord a, Num a) => [a] -> a -> [a] -> [a]
g x y z
=
either
::
either f _ (Left x)
either _ g (Right y)
Ord a => Int -> [a] -> a -> Bool
=
=
if sum x < y then x ++ z else tail x
(a -> c) -> (b -> c) -> Either a b -> c
f x
g y
5
Dr. A. Raschke
Prof. Dr. H. Partsch
Aufgabe 6
Paradigmen der Programmierung
SS 11 Prüfungsklausur
25.07.2011
(9+11 = 20 Punkte)
a) Definieren Sie eine Funktion zipWith :: (a -> b -> c) -> [a] -> [b] -> [c],
welche als eine Verallgemeinerung der Funktion zip zwei Listen mittels einer übergebenen Funktion zu einer zusammenfügt. Die Ergebnisliste soll wie bei zip die
Länge der kürzeren Argumentliste besitzen.
Beispiel:
zipWith (+) [1,2,3] [4,5,6,7,8] = [5,7,9]
zip = zipWith (,)
Geben Sie für diese Funktion drei verschiedene Implementierungen an:
i) mittels expliziter Rekursion und
ii) durch eine Listenkomprehension und Verwendung von zip und
iii) durch eine geeignete Anwendung von map und zip
Hinweis: Für diese Aufgabe können die Definitionen des Haskell Prelude-Moduls
benutzt werden. Wenn Sie darüber hinaus Hilfsfunktionen verwenden, so müssen
Sie diese auch definieren.
i) zipWith f (x:xs) (y:ys) = f x y : zipWith f xs ys
zipWith _ _ _
= []
-- auch
zipWith
zipWith
zipWith
korrekt:
f [] _
= []
f _ []
= []
f (x:xs) (y:ys) = f x y : zipWith f xs ys
ii) zipWith f xs ys = [f x y | (x,y) <- zip xs ys]
iii) zipWith f xs ys = map (\(x,y) -> f x y) (zip xs ys)
6
Dr. A. Raschke
Prof. Dr. H. Partsch
Paradigmen der Programmierung
SS 11 Prüfungsklausur
25.07.2011
b) Die Prüfziffer bei einer ISBN-10 Nummer berechnet sich, indem die vorangehenden 9 Ziffern, gewichtet mit ihrer jeweiligen Position (beginnend bei 1), aufaddiert werden und der Rest der ganzzahligen Division durch 11 genommen wird
(ein Rest von 10 wird üblicherweise als Ziffer ’X’ geschrieben, dies muss hier aber
nicht beachtet werden):
!
9
X
z10 =
mod 11
i · zi
i=1
Definieren Sie eine Funktion isbn10 :: [Int] -> Int, welche eine Liste von
neun Ziffern bekommt und daraus die ISBN-10 Prüfziffer berechnet. Geben Sie
für diese Funktion zwei unterschiedliche Implementierungen an:
i) Unter Verwendung einer rekursiven Hilfsfunktion über die Liste mit einem
inkrementellen (also hochzählendem) Parameter und
ii) mittels geschickter Funktionskomposition und der in a) definierten Funktion
zipWith.
Hinweis: Für diese Aufgabe können die Definitionen des Haskell Prelude-Moduls
benutzt werden. Wenn Sie darüber hinaus Hilfsfunktionen verwenden, so müssen
Sie diese auch definieren.
i) isbn10 :: [Int] -> Int
isbn10 xs = makeSum 1 xs ‘mod‘ 11
where makeSum _ []
= 0
makeSum i (x:xs) = i*x + makeSum (i+1) xs
ii) isbn10 = (‘mod‘ 11) . sum . zipWith (*) [1..]
7
-- [1,2,3,4,5,6,7,8,9]
Dr. A. Raschke
Prof. Dr. H. Partsch
Aufgabe 7
Paradigmen der Programmierung
SS 11 Prüfungsklausur
25.07.2011
(6+10+3 = 19 Punkte)
Gegeben sei folgender Datentyp zur Repräsentation von booleschen Ausdrücken:
data BoolExpr = Value Bool
| And BoolExpr BoolExpr
| Not BoolExpr
Der Ausdruck (¬False ∧ True) ∧ True wird z.B. dargestellt als:
And (And (Not (Value False)) (Value True)) (Value True)
a) Schreiben Sie eine rekursive Funktion eval :: BoolExpr -> Bool, die einen
booleschen Ausdruck auswertet.
eval
eval
eval
eval
:: BoolExpr
(Value b)
(And e1 e2)
(Not e)
-> Bool
= b
= (eval e1) && (eval e2)
= not (eval e)
b) Definieren Sie eine Funktion foldBoolExpr zur Faltung boolescher Ausdrücke
gemäß der in der Vorlesung dargestellten Regeln zur Faltung von allgemeinen
Datentypen. Geben Sie auch den Typ Ihrer Funktion an.
foldBoolExpr ::
->
->
->
->
(Bool -> a)
(a -> a -> a)
(a -> a)
BoolExpr
a
foldBoolExpr val_f and_f not_f expr = f expr
where f (Value b)
= val_f b
f (And e1 e2) = and_f (f e1) (f e2)
f (Not e)
= not_f (f e)
c) Definieren Sie eval als Instanz von foldBoolExpr.
eval = foldBoolExpr id (&&) not
8
Dr. A. Raschke
Prof. Dr. H. Partsch
Aufgabe 8
Paradigmen der Programmierung
SS 11 Prüfungsklausur
25.07.2011
(6 Punkte)
Ein Gray-Code ist eine Sequenz von binären Codewörtern mit der Eigenschaft, dass
sich benachbarte Codewörter lediglich um ein einziges Bit unterscheiden. Definieren Sie
eine Funktion gray :: Int -> [String], die für n ≥ 1 die n-Bit Gray-Code Sequenz
zurückliefert.
Beispiel:
gray 1 = ["0","1"]
gray 2 = ["00","01","11","10"]
gray 3 = ["000","001","011","010","110","111","101","100"]
Überlegen Sie sich hierzu, wie der jeweilige n-Bit Code aus dem (n − 1)-Bit Code erzeugt
werden kann.
Hinweis: Für diese Aufgabe können die Definitionen des Haskell Prelude-Moduls benutzt
werden. Wenn Sie darüber hinaus Hilfsfunktionen verwenden, so müssen Sie diese auch
definieren.
gray :: Int -> [String]
gray 0 = [""]
gray n = let xs = gray (n-1) in map (’0’:) xs ++ map (’1’:) (reverse xs)
oder mit Listenkomprehension:
gray :: Int -> [String]
gray 0 = [""]
gray n = [ ’0’ : x | x <- prev ] ++ [ ’1’ : x | x <- reverse prev ]
where prev = gray (n-1)
Auch korrekt: ohne 0-Bit Codewort
gray 1 = ["0", "1"]
gray n = ...
9
Dr. A. Raschke
Prof. Dr. H. Partsch
Aufgabe 1
Paradigmen der Programmierung
SS 11 Prüfungsklausur
26.09.2011
(6+9 = 15 Punkte)
Haskell: Typisierung
a) Bestimmen Sie jeweils den Typ der folgenden Haskell-Ausdrücke:
map putChar [’a’..’z’]
::
[IO ()]
(const ’1’, map (const "2")) ::
(a -> Char, [b] -> [String])
[Left "Error", Right True]
[Either String Bool]
::
b) Gegeben seien die folgenden Funktionsdefinitionen. Bestimmen Sie jeweils den
allgemeinsten Typ der Funktionen. Denken Sie auch an eventuelle Klasseneinschränkungen.
f
f x y
g
g w x y z
::
=
::
=
nub
::
nub
=
err
::
err (Left msg)
=
err (Right val)
=
[[a]] -> [[a]] -> [a]
concat (x ++ y)
(Ord a, Num b) => a -> a -> [b] -> [b] -> b
if w < x then product y else sum z
Eq a => [a] -> [a]
foldr (\x xs -> if x ‘elem‘ xs then xs
else x:xs) []
Show a => (Either a b) -> IO (Maybe b)
do putStrLn (show msg)
return Nothing
do putStrLn "Success!"
return (Just val)
0
Dr. A. Raschke
Prof. Dr. H. Partsch
Aufgabe 2
Paradigmen der Programmierung
SS 11 Prüfungsklausur
26.09.2011
(5+6+4 = 15 Punkte)
Haskell: Listen und IO
Für die folgenden Aufgaben dürfen Sie alle auf dem Übersichtsblatt angegebenen vordefinierten Funktionen verwenden. Alle anderen verwendeten Funktionen müssen explizit
definiert werden.
a) Schreiben Sie eine Funktion getNth :: [a] -> Int -> Maybe a, welche als ersten Parameter eine Liste l und als zweiten Parameter eine ganze Zahl n erhält.
Diese Funktion liefert das n-te Element (bei 0 angefangen zu zählen) der übergebenen Liste. Kann dieser Wert nicht ermittelt werden (übergebener Index zu
groß oder zu klein), soll Nothing zurückgeliefert werden.
Beispiel:
Prelude> getNth "Alexander" 5
Just ’n’
getNth
getNth
getNth
getNth
[] _ =
_ n |
(x:xs)
(x:xs)
Nothing
n < 0 = Nothing
0 = Just x
n = getNth xs (n-1)
b) Schreiben Sie eine Funktion getandremoveNth :: [a] -> Int -> (Maybe a,[a])
welche ähnlich zu der Funktion getNth funktioniert, aber zusätzlich eine neue Liste zurückliefert, in der das n-te Element (bei 0 angefangen zu zählen) entfernt
wurde. Sie dürfen dazu auch die Funktion getNth benutzen. Bei einem fehlerhaften Index (zu groß oder zu klein) soll Nothing und die ursprüngliche Liste
zurückgeliefert werden.
Beispiel:
Prelude> getandremoveNth "Alexander" 5
(Just ’n’,"Alexader")
getandremoveNth l n = let elem = getNth l n in
case elem of
Nothing -> (Nothing, l)
Just x -> (elem, (take n l) ++ (drop (n+1) l))
1
Dr. A. Raschke
Prof. Dr. H. Partsch
Aufgabe 3
Paradigmen der Programmierung
SS 11 Prüfungsklausur
26.09.2011
(9+12+6+3 = 30 Punkte)
Haskell: Bäume und Faltung
Eine Schlauchleitung bei der Feuerwehr besteht (stark vereinfacht) aus Schläuchen, Verteilern, und Strahlrohren. Die Schläuche und Strahlrohre haben zwei verschiedene Größen, welche mit B und C bezeichnet werden. Ein Verteiler hat einen B-Eingang, links und
rechts C-Abgänge und in der Mitte einen B-Abgang. Von den Schlauchgrößen abgesehen,
können Schläuche und Verteiler beliebig kombiniert werden. Ein Strahlrohr kann geöffnet (true) oder geschlossen (false) sein. An einem Verteiler sind immer alle Abgänge
offen.
Diese Zusammenhänge können zum Beispiel mit folgenden Datentypen beschrieben werden:
data Groesse = B | C
deriving Eq
data Leitung = Rohr Groesse Bool
| Schlauch Groesse Leitung
| Verteiler Leitung Leitung Leitung
Die Konfiguration der im Bild skizzierten Schlauchleitung wird dann durch folgenden
Ausdruck dargestellt:
bsp = Schlauch B (Verteiler (Schlauch C (Schlauch C (Rohr C True)))
(Schlauch B (Rohr B True))
(Rohr C False))
Mit diesen Datentypen ist es möglich, falsche Schlauch-/Anschlussgrößen zusammenzusetzen. Zum Beispiel macht Schlauch B (Schlauch C (Schlauch B)) in der Realität
keinen Sinn. Es kann aber für alle folgenden Aufgaben davon ausgegangen werden, dass
die jeweils übergebene Schlauchleitung korrekt zusammengesetzt ist.
3
Dr. A. Raschke
Prof. Dr. H. Partsch
Paradigmen der Programmierung
SS 11 Prüfungsklausur
26.09.2011
a) Schreiben Sie eine rekursive Funktion gesamtlaenge :: Leitung -> Int, die
die Gesamtlänge der eingesetzten Schläuche bestimmt.
C-Schläuche haben eine normierte Länge von 15m, B-Schläuche eine Länge von
20m. Die Länge von Strahlrohren und Verteilern wird bei der Längenbestimmung
nicht berücksichtigt.
Beispiel:
Prelude> gesamtlaenge bsp
70
gesamtlaenge (Schlauch x l) | x == B = gesamtlaenge
| x == C = gesamtlaenge
gesamtlaenge (Verteiler l1 l2 l3)
= gesamtlaenge
gesamtlaenge
gesamtlaenge
gesamtlaenge _
= 0
l + 20
l + 15
l1 +
l2 +
l3
b) Definieren Sie eine Funktion foldLeitung zur Faltung des obigen Datentyps gemäß der in der Vorlesung dargestellten Regeln zur Faltung von allgemeinen Datentypen. Geben Sie auch den Typ Ihrer Funktion an.
foldLeitung :: (Groesse -> Bool -> a) ->
(Groesse -> a -> a) ->
(a -> a -> a -> a) ->
Leitung -> a
foldLeitung rf sf vf l = f l
where f (Rohr g b)
= rf g b
f (Schlauch g l)
= sf g (f l)
f (Verteiler l1 l2 l3) = vf (f l1) (f l2) (f l3)
4
Dr. A. Raschke
Prof. Dr. H. Partsch
Paradigmen der Programmierung
SS 11 Prüfungsklausur
26.09.2011
c) Definieren Sie eine Funktion wassermenge :: Leitung -> Int als Instanz von
foldLeitung, welche die aktuell abgegebene Wassermenge einer Schlauchleitung
bei einem festgelegten Druck angibt.
Folgende Faustwerte werden dafür eingesetzt: C-Strahlrohre geben 100 l/min
Wasser ab, B-Strahlrohre 400 l/min. Verteiler und Schläuche werden nicht berücksichtigt (obwohl sie in der Realität natürlich einen Einfluss haben).
Bei der Berechnung soll allerdings schon berücksichtigt werden, ob das entsprechende Strahlrohr geöffnet oder geschlossen ist!
Beispiel:
Prelude> wassermenge bsp
500
wassermenge :: Leitung -> Int
wassermenge = foldLeitung (\g b -> if b then
(if g==C then 100 else 400)
else 0)
(\g l -> l)
(\l1 l2 l3 -> l1 + l2 + l3)
d) Wie müssten die Datentypdefinitionen verändert werden, damit nur noch korrekte Schlauchleitungen instanziiert werden können? Es soll also nicht mehr möglich sein, dass zum Beispiel nach einem B-Schlauch eine Leitungskomponente
(Schlauch oder Rohr) mit C-Größe angegeben werden kann. Geben Sie Vorschläge für die Datentypdefinitionen an!
data BLeitung =
|
|
data CLeitung =
|
BRohr Bool
BSchlauch BLeitung
Verteiler CLeitung BLeitung CLeitung
CRohr Bool
CSchlauch CLeitung
5
Herunterladen