Tutoraufgabe 1 (Auswertungsstrategie): Lösung:

Werbung
Prof.aa
Dr. J. Giesl
Programmierung WS12/13
Tutoriumslösung - Übung 10 (Abgabe 11.01.2013)
M. Brockschmidt, F. Emmes, C. Otto, T. Ströder
Tutoraufgabe 1 (Auswertungsstrategie):
Gegeben sei das folgende Haskell-Programm:
absteigend :: Int -> [ Int ]
absteigend 0 = []
absteigend n = n : absteigend (n -1)
produkt :: [ Int ] -> Int
produkt [] = 1
produkt ( x : xs ) = x * produkt xs
summe :: [ Int ] -> Int
summe xs = summe ’ xs 0
where summe ’ []
a = a
summe ’ ( x : xs ) a = summe ’ xs ( a + x )
Die Funktion absteigend berechnet die absteigende Liste der natürlichen Zahlen bis hinunter zu 1. Zum
Beispiel berechnet absteigend 5 die Liste [5,4,3,2,1]. Die Funktion produkt multipliziert die Elemente
einer Liste, beispielsweise ergibt produkt [3,5,2,1] die Zahl 30. Die Funktion summe addiert die Elemente
einer Liste. Zum Beispiel liefert summe [5,2,7] den Wert 14.
Geben Sie alle Zwischenschritte bei der Auswertung der folgenden Ausdrücke an:
1. produkt (absteigend 2)
2. summe (absteigend 2)
Beachten Sie, dass Haskell eine Leftmost-Outermost Auswertungsstrategie besitzt. Allerdings sind Operatoren
wie * und +, die auf eingebauten Zahlen arbeiten, strikt, d.h. hier müssen vor Anwendung des Operators seine
Argumente vollständig ausgewertet worden sein.
Lösung:
produkt (absteigend 2)
→ produkt (2 : absteigend (2-1))
→ 2 * produkt (absteigend (2-1))
→ 2 * produkt (absteigend 1)
→ 2 * produkt (1 : absteigend (1-1))
→ 2 * (1 * produkt (absteigend (1-1)))
→ 2 * (1 * produkt (absteigend 0)))
→ 2 * (1 * produkt [])
→ 2 * (1 * 1)
→2 * 1
→2
summe (absteigend 2)
→ summe’ (absteigend 2) 0
→ summe’ (2 : absteigend (2-1)) 0
→ summe’ (absteigend (2-1)) (0+2)
→ summe’ (absteigend 1) (0+2)
→ summe’ (1 : absteigend (1-1)) (0+2)
→ summe’ (absteigend (1-1)) ((0+2)+1)
→ summe’ (absteigend 0) ((0+2)+1)
→ summe’ [] ((0+2)+1)
→ (0+2)+1
1
Programmierung WS12/13
Tutoriumslösung - Übung 10 (Abgabe 11.01.2013)
→ 2+1
→3
Tutoraufgabe 3 (Listen):
Seien x, y ganze Zahlen vom Typ Int und xs und ys Listen der Längen n und m vom Typ [Int].
Welche der folgenden Gleichungen zwischen Listen sind richtig und welche nicht? Begründen Sie Ihre Antwort.
Falls es sich um syntaktisch korrekte Ausdrücke handelt, geben Sie für jede linke und rechte Seite auch an, wie
viele Elemente in der jeweiligen Liste enthalten sind und welchen Typ sie hat.
Beispiel : Die Liste [[1,2,3],[4,5]] hat den Typ [[Int]] und enthält 2 Elemente.
Hinweise:
• Hierbei steht ++ für den Verkettungsoperator für Listen. Das Resultat von xs ++ ys ist die Liste, die
entsteht, wenn die Elemente aus ys — in der Reihenfolge wie sie in ys stehen — an das Ende von xs
angefügt werden.
Beispiel : [1,2] ++ [1,2,3] = [1,2,1,2,3]
• Falls linke und rechte Seite gleich sind, genügt eine Angabe des Typs und der Elementzahl
a) x:xs = [x] ++ xs
b) (x:y):xs = x:y:xs
c) [x,y,xs] = x:y:xs
d) x:y:((x:[x]) ++ xs) = [x,y,x] ++ (x:xs)
e) []:[[],[[1]]] = [[],[]]:[[[1]]]
Lösung:
a) Beide Ausdrücke repräsentieren die gleichen Listen der Länge n + 1 und vom Typ [Int].
b) Der erste Ausdruck ist nicht typkorrekt, da im Teilausdruck x:y die Variable y keine Liste ist. Sie
kann somit nicht als zweites Argument des Konstruktors “:” verwendet werden. Der rechte Ausdruck ist
typkorrekt und repräsentiert eine Liste der Länge n + 2 vom Typ [Int]. Die Ausdrücke sind also nicht
gleich.
c) Der linke Ausdruck ist nicht typkorrekt, da x und y nicht den gleichen Typ wie xs haben, aber beide in
der gleichen Liste enthalten sind. Der rechte Ausdruck repräsentiert eine Liste der Länge n + 2 und ist
vom Typ [Int]. Die Ausdrücke sind also nicht gleich.
d) Beides sind typkorrekte Listenausdrücke (äquivalent zu [x,y,x,x] ++ xs der Länge n + 4 und ebenfalls
vom Typ [Int]. Die Ausdrücke sind also gleich.
e) Der linke Ausdruck ergibt ausgeschrieben die Liste [[],[],[[1]]], also eine dreielementige Liste, die
Listen von Listen enthält. Der genaue Typ der innersten Liste ist [Int]. Der Typ des gesamten Ausdrucks
ist demnach [[[Int]]]. Der zweite Ausdruck ergibt ausgeschrieben die Liste [[[],[]],[[1]]], also eine
zweielementige Liste, die Listen von Listen enthält. Auch hier ist der Typ der innersten Liste [Int] und
der Typ des gesamten Ausdrucks ist [[[Int]]]. Da die beiden Ausdrucke zwar den gleichen Typ haben,
aber nicht die gleichen Listen darstellen, sind die Ausdrücke also nicht gleich.
2
Programmierung WS12/13
Tutoriumslösung - Übung 10 (Abgabe 11.01.2013)
Tutoraufgabe 5 (Programmieren):
Implementieren Sie alle der im Folgenden beschriebenen Funktionen in Haskell. Geben Sie jeweils auch die
Typdeklarationen an. Verwenden Sie außer Listenkonstruktoren [] und : (und deren Kurzschreibweise) und
Vergleichsoperatoren wie <=, ==,. . . keine vordefinierten Funktionen (dies schließt auch arithmetische Operatoren ein), außer denen, die in den jeweiligen Teilaufgaben explizit erlaubt werden.
a) sekunden h m s
Gibt die Anzahl der Sekunden zurück, die in h Stunden, m Minuten und s Sekunden vergehen. So
berechnet zum Beispiel sekunden 5 4 3 den Wert 18243. Die Funktion darf sich auf negativen Eingaben
beliebig verhalten. Sie dürfen hier + und * verwenden.
b) turm x y
Berechnet den Potenzturm x ↑↑ y. Der Potenzturm ist die logische Weiterentwicklung von Multiplikation
und Potenzfunktion:
Multiplikation
a·n
:=
a + a + ··· + a
{z
}
|
n
Potenz
n
a
:=
a
| · a ·{z. . . · a}
n
a
Potenzturm
a ↑↑ n
:=
a
|
·
··
(aa )
{z
n
!
}
Beispiele:
2 2(2 )
• 2 ↑↑ 4 = 2
4
= 2(2
)
= 216 = 65.536
• 3 ↑↑ 3 = 7.625.597.484.987
Die Funktion darf sich auf negativen Eingaben beliebig verhalten. Sie dürfen auf - und ^ (zur Berechnung
der Potenz) zurückgreifen.
Hinweise:
• Auch in Haskell gibt es unterschiedliche Integer-Datentypen mit verschiedenen Wertebereichen, weshalb in Ihrer Lösung vermutlich turm 3 3 nicht das erwartete Ergebnis 7625597484987 liefert.
Wenn Sie den Datentyp Integer statt Int für die Darstellung ganzer Zahlen verwenden, vermeiden
Sie das Problem.
c) wurzel x
Berechnet die abgerundete dritte (!) Wurzel aus x. Zum Beispiel liefert der Aufruf wurzel 124 den Wert
4. Die Funktion darf sich auf negativen Eingaben beliebig verhalten. Sie dürfen hier - und * verwenden.
d) getEnd xs
Berechnet das letzte Element der Int-Liste xs. Beispielsweise berechnet getEnd [12, 7, 23] den Wert
23. Die Funktion darf sich auf leeren Listen beliebig verhalten.
e) insertEnd x ys
Berechnet die Int-Liste, die entsteht, wenn man den Wert x an das Ende der Int-Liste ys einfügt.
Beispielsweise berechnet insertEnd [12, 7] 23 die Liste [12, 7, 23].
f ) anzahl x ys
Berechnet die Anzahl der Vorkommen von x in der Int-Liste ys. Zum Beispiel liefert der Aufruf anzahl
3 [1,2,3,4,5,4,3,2,1] den Wert 2. Sie dürfen hier + verwenden.
g) einfuegen x ys
Berechnet die Int-Liste, die entsteht, wenn man den Wert x so in die sortierte Int-Liste ys einfügt, dass
diese anschließend weiterhin sortiert ist. Zum Beispiel liefert der Aufruf einfuegen 5 [1,3,5,7] den
Wert [1,3,5,5,7].
3
Programmierung WS12/13
Tutoriumslösung - Übung 10 (Abgabe 11.01.2013)
h) insSort xs
Sortiert die Int-Liste xs. Verwenden Sie dabei die Funktion einfuegen. Der Aufruf insSort [5,3,1,8]
liefert dann beispielweise den Wert [1,3,5,8].
i) zipping xs ys
Berechnet die Kombination der beiden Int-Listen xs und ys im Reißverschlussprinzip. Das heißt, dass
das Ergebnis zuerst das erste Element von xs, dann das erste Element von ys, dann das zweite Element
von xs usw. enthält. Wenn eine der beiden Listen leer ist, sollen nur noch Elemente aus der anderen Liste
folgen. Beispielsweise berechnet zipping [1,2,5,8,7,6] [3,9,4] die Liste [1,3,2,9,5,4,8,7,6].
j) flach xs
Berechnet für eine Liste von Int-Listen eine “flache” Liste, die die Elemente der inneren Listen der
Eingabe xs in der ursprünglichen Reihenfolge enthält. Der Aufruf flach [[1,5,2],[],[2,3]] liefert
zum Beispiel den Wert [1,5,2,2,3].
Lösung:
-- a
sekunden :: Int -> Int -> Int -> Int
sekunden h m s = 60*60* h + 60* m + s
-- b
turm :: Integer -> Integer -> Integer
turm _ 0 = 1
turm x y = x ^ ( turm x (y -1))
-- c
wurzel :: Int -> Int
wurzel 0 = 0
wurzel x = wurzelH x
where wurzelH :: Int -> Int
wurzelH w | w * w * w <= x = w
| otherwise = wurzelH (w -1)
-- d
getEnd :: [ Int ] -> Int
getEnd [ x ] = x
getEnd ( _ : xs ) = getEnd xs
-- e
insertEnd :: Int -> [ Int ] -> [ Int ]
insertEnd x
[] = [ x ]
insertEnd x ( y : ys ) = y : insertEnd x ys
-- f
anzahl :: Int -> [ Int ] -> Int
anzahl _ []
= 0
anzahl x ( y : ys ) | x == y
= 1 + anzahl x ys
| otherwise
=
anzahl x ys
-- g
einfuegen :: Int -> [ Int ] -> [ Int ]
einfuegen x []
= [x]
einfuegen x ( y : ys ) | x < y
= x : y : ys
| otherwise = y : einfuegen x ys
4
Programmierung WS12/13
Tutoriumslösung - Übung 10 (Abgabe 11.01.2013)
-- h
insSort :: [ Int ] -> [ Int ]
insSort []
= []
insSort ( x : xs ) = einfuegen x ( insSort xs )
-- i
zipping :: [ Int ] -> [ Int ] -> [ Int ]
zipping []
ys = ys
zipping ( x : xs ) ys = x : zipping ys xs
-- j
flach
flach
flach
flach
:: [[ Int ]] -> [ Int ]
[]
= []
(
[]: ys ) = flach ys
(( x : xs ): ys ) = x : flach ( xs : ys )
5
Herunterladen