------------------------------------------------------------------------ Seminar Theoretische Informatik \ \ -- "Funktionale Programmierung mit Haskell" \ \ ---- Universität Potsdam SS 2014 / /\ --- Tim Richter / Mario Frank / / \ --- Übungsblatt 3 (Listen) -- Abgabe bis: 28.05.2014, 23:59 -- Name: -- Erreichte Punkte: / 14 ---------------------------------------------------------------------module Uebung3 where import Prelude data Nat = O | S Nat deriving (Show ) intToNat :: Int → Nat intToNat n | (n < 0) = ⊥ | (n ≡ 0) = O | otherwise = S (intToNat (n − 1)) natToInt :: Nat → Int natToInt O =0 natToInt (S n) = 1 + (natToInt n) 1 Vorbemerkung Beweise sind stets im Stil des ”equational reasoning”, wie es im Buch eingeführt wird, zu führen. Insbesondere ist für jede Gleichung in geschweiften Klammern hinter dem Gleichheitszeichen eine Begründung anzugeben. Abweichung von dieser Form führt zu Punktverlust! 2 Listenoperationen (1+2+2+2 pt) 2.1 Last Gegeben seien die folgenden Definitionen für die Funktion, die das letzte Element einer Liste zurückgibt: last 0 (x : xs) = if null xs then x else last 0 xs last 00 (x : xs) = if xs ≡ [ ] then x else last 00 xs Der Unterschied zwischen last 0 und last 00 besteht darin, dass sich die Typen unterscheiden. last 0 :: [a ] → a last 00 :: (Eq a) ⇒ [a ] → a Die Typ der Funktion last 00 beschränkt die Eingabe auf Listen von Elementen, die zum Typ Eq gehören. Geben Sie einen Ausdruck n an, auf dem sich last 0 und last 00 unterschiedlich verhalten. (1 pt) 1 2.2 Verkettung Beweisen Sie, dass folgende Gleichung gilt: (2 pt) concat (xss ++ yss) = concat xss ++ concat yss concat ist dabei als foldr (+ +) [ ] und (++) durch Rekursion über das erste Argument definiert (siehe Prelude). Schreiben Sie diese Definitionen aus und geben Sie den einzelnen Regeln Label, um im Beweis auf sie referenzieren zu können! 2.3 Halbieren einer Liste Definieren Sie eine Funktion splitHalf :: [a ] → (([a ], [a ]), Maybe a) splitHalf = ⊥ die eine Liste ”in der Mitte teilt”: Ist splitHalf as = ((bs, cs), m), so sollen die Listen bs und cs gleich lang sein und es soll, falls m = Just a ist, as = bs ++ [a ] ++ cs und sonst as = bs ++ cs gelten. (2 pt) 2.4 Bedingtes Umkehren einer Liste Definieren Sie eine Funktion revEven :: [a ] → [a ] revEven = ⊥ die alle Listen gerader Länge umkehrt und alle anderen Listen unverändert lässt. Benutzen Sie splitHalf und ”pattern guards” (siehe http://www.haskell.org/haskellwiki/Pattern_guard). Verwenden Sie weder where noch let! (2 pt) 3 Map und Filter (1+1+2 pt) 3.1 Map 1. Geben Sie den Typen von map map an! (1 pt) 2. Beweisen Sie, dass folgende Gleichungen gelten: map f (xs ++ ys) = map f xs ++ map f ys (1 pt) map f . concat = concat . map (map f ) (2 pt) Führen Sie den Beweis der zweiten Gleichung, indem Sie unter Benutzung der ersten Gleichung und geeigneter Gesetze zeigen, dass beide Seiten sich als dieselbe foldr -Instanz schreiben lassen. 3.2 Filter (1 pt) Die Prelude-Funktion filter :: (a → Bool ) → [a ] → [a ] kann mit Hilfe von concat und map konstruiert werden: filter 0 p = concat ◦ map box where box x = ⊥ Vervollständigen Sie die Definition für box . (1 pt) 2 4 Folds (3 pt) Die Funktionen takeWhile und dropWhile sind den Funktionen take und drop ähnlich. Statt eines Int-Indexes nehmen sie jedoch einen Boole’schen Ausdruck als ersten Parameter. Das Ergebnis von takeWhile p xs ist das längste Initial-Segment von xs, dessen Elemente sämtlich die Bedingung p erfüllen. Zum Beispiel ist takeWhile even [2,4,7,4,1,6] = [2,4] 1. Definieren Sie filter p als Instanz von foldr (1 pt) 2. Definieren Sie takeWhile als Instanz von foldr (1 pt) 3. Kann dropWhile als Instanz einer Fold-Funktion definiert werden? Implementieren oder begründen Sie! (1 pt) 5 Hyperoperationen (just for fun) Ausgehend von der Beobachtung, dass Multiplikation ”iterierte Addition” und Potenzieren ”iteriertes Multiplizieren” ist, definiert man die Folge der Hyperoperation (siehe Wikipedia: http://en.wikipedia.org/ wiki/Hyperoperation). Definieren Sie unter Verwendung von foldr1 und foldNat foldNat :: a → (a → a) → Nat → a foldNat s f O = s foldNat s f (S m) = f $ foldNat s f m eine Funktion hop :: Nat → Integer → Integer → Integer hop = ⊥ derart, dass a‘hop n‘b für b > 1 das Ergebnis der Anwendung der (n+1)ten (sic!) Hyperoperation auf das Paar (a, b) ist! Für b < 1 darf die Funktion undefiniert sein. 3