WS 2009/2010 Gruppe: TutorInnen Praktische Informatik 3 Tutor: Lösung für Übungsblatt 1 Aufgabe 1 Berthold Hoffmann Abgabe: 29.10.2009 Natürlich! Der Typ Nat der natürlichen Zahlen enthält die Zahl Null, dargestellt durch den Konstruktor Z (für engl. zero) und beliebig viele Nachfolger (engl. successor) von Null, die als rekursive Anwendungen des Konstruktors S repräsentiert werden. data Nat = Z | S Nat -- zero -- successor Die Addition von natürlichen Zahlen kann so definiert werden: plus :: Nat → Nat → Nat plus Z y=y plus (S x) y = S (plus x y) 1. Analog dazu kann auch die Funktion times für die Multiplikation natürlicher Zahlen definiert werden: times :: Nat → Nat → Nat times Z y=Z times (S x) y = plus (times x y) y 2. Dann kann die Fakultät n! so definiert werden: fac :: Nat → Nat fac Z =S Z fac (S n) = times (fac n) (S n) −− 0! = 1 −− n! = (n-1)! * n 3. Um die Rechtsneutralität von plus zu zeigen, muss man den Satz 1.1 auf Seite 7 nur “intelligent umformaen”. Theorem 1 (Null ist rechtsneutral für die Addition) ∀n ∈ Nat : plus n Z = Z Proof. Durch Induktion über die Struktur von Nat. Induktionsanfang. Sei n = Z in (1). Dann gilt: plus Z Z = Z 1. Gleichung von plus Induktionsannahme. Gelte (1) für beliebige Zahlen n ≥ 0. (1) Tutor: , Gruppe: TutorInnen, Berthold Hoffmann et. al. PI 3, WS 2009/2010 Induktionsschritt. Wir zeigen, dass dann (1) für eine beliebige Zahl n + 1 gilt. So eine Zahl hat oBdA die Form S n. Dann gilt: plus (S n) Z = S (plus n Z) 2. Gleichung von plus = S (plus Z n) nach Induktionsannahme = 1. Gleichung von plus S n Damit gilt (1) für beliebige n ∈ Nat. Aufgabe 2 Verkehrt! Listen sind ein polymorpher rekursiver Datentyp: Eine Liste über einer Typvariable t ist entweder leer (das Atom Empty), oder sie wird (mit dem Datenkonstruktor Cons) aus einem Element des Typs t und einer Liste über t gebildet. data List t = Empty | Cons t (List t) Die Verkettung von Listen kann so definiert werden: cat :: List t → List t → List t cat Empty ys = ys cat (Cons h t) ys = Cons h (cat t ys) 1. Nun kann auch die Funktion rev für die Umkehrung von Listen so definiert werden: rev :: List t → List t rev Empty = Empty rev (Cons h t) = cat (rev t) (Cons h Empty) 2. Sei n die Länge der umzukehrenden Liste. Jeder der n rekursiven Aufruf von rev ruft die Funktion cat auf. Dabei haben die ersten Argumentn von cat die Längen n − 1, n − 2, . . . , 1, 0, sind also proportional zu n. Also hat jeder Aufruf von cat linearen Zeitaufwand, und rev insgesamt quadratischen Zeitaufwand. Da in jedem rekursiven Aufruf die Konstruktoren Cons und Empty aufgerufen werden, konstruiert rev 2n Knoten. Da jeder Aufruf von cat ℓ ℓ′ für jedes Element von ℓ ein Cons konstruiert, ist auch der Platzbedarf von rev insgesamt quadratisch. Aufgabe 3 Hoch hinaus! 1. Die Funktion iteration, die eine Funktion f :: a → a n mal auf ein Argument x anwendet, kann so definiert werden: iteration :: Nat → (t → t) → t → t iteration Z f x=x iteration (S n) f x = f (iteration n f x) 2. Die Funktion twice kann so definiert werden 2 PI 3, WS 2009/2010 Tutor: , Gruppe: TutorInnen, Berthold Hoffmann et. al. twice f x = iteration (S (S Z) f x (Man könnte auch schreiben: twice f =iteration (S (S Z) f.) 3. Folgende Eigenschaft beschreibt einen Zusammenhang zwischen iteration und map: Die n-fache Iteration der Funktion map f entspricht einem einfachen Aufruf von map mit n-fach iteriertem f : ∀n ∈ N, f ∈ α → α, ℓ ∈ List α : iteration n (map f ) ℓ = map (iteration n f ) ℓ Kürzer geht es auch: ∀n ∈ N, f ∈ α → α : iteration n (map f ) = map (iteration n f ) 3