Lösungen zum 4. Aufgabenblatt zur Vorlesung Informatik A (Autor: Sascha Meiers) 1. Einfaches Haskell Die Lösung wurde freundlicherweise bereitgestellt von M. Can und L. Thomas. threeDiff :: Int -> Int -> Int -> Bool threeDiff a b c = a /= b && a /= c && b /= c -- Die Funktion ist nur dann True, falls a /= b, a /= c und b /= c gilt. threeEqual :: Int -> Int -> Int -> Bool threeEqual a b c = a == b && b ==c -- Die Funktion ist nur dann True, falls a = b = c gilt. howManyDiff :: Int -> Int -> Int -> Int howManyDiff a b c | threeDiff a b c = 3 | threeEqual a b c = 1 | otherwise = 2 2. Klammerung testen (a) Schreiben Sie eine Funktion klammerTest :: String -> Bool, die testet, ob die in einem Eingabestring vorkommenden öffnenden und schließenden runden Klammern 0 (0 bzw. 0 )0 einen korrekten Klammerausdruck bilden. Korrekte Klammerausdrücke sind dadurch gekennzeichnet, dass in jedem Präfix (Anfangsstück) des Strings mindestens so viele öffnende wie schließende Klammern auftreten und insgesamt es gleich viele öffnende und schließende Klammern gibt. Definieren Sie ggf. geeignete Hilfsfunktionen. Lösung: Die Lösung wurde freundlicherweise bereitgestellt von B. Jeschke und M. Möllenberg. Sie beruht auf einem Int, der mit dem String übergeben wird und die Differenz der Zahl der öffnenden und der Zahl der schließenden Klammern speichert. Dieser muss am Ende 0 sein (# schließende Klammern = # öffnende Klammern) und darf zwischendurch nicht unter 0 sinken (mindestens soviele öffnende wie schließende Klammern in jedem Präfix des Strings). klammerTest :: String -> Bool klammerTest a = test a 0 test :: String -> Int -> Bool test [] n = n == 0 test (x:xs) n | | | | n < 0 = False x == ’(’ = test xs (n+1) x == ’)’ = test xs (n-1) otherwise = test xs n ----- Falls n<0 soll er sofort abbrechen n wird 1 hochgezählt n wird 1 runtergezählt arbeite mit dem Rest weiter (b) Die Menge der korrekt geklammerten, nichtleeren Wörter über dem Alphabet Σ = {x1 , ..., xn , (, )} ist die Menge derjenigen Wörter, die sich durch endlich oftes Anwenden der folgenden Regeln erzeugen lassen. i. Jeder einzelne Buchstabe aus {x1 , ..., xn } sowie das Wort () sind korrekte Klammerausdrücke. ii. Falls t ein korrekter Klammerausdruck ist, dann ist auch (t) ein k. KA. iii. Falls t1 und t2 korrekte KA.sind, dann ist auch die Konkatenation t1 ◦ t2 ein korrekter KA. 3. Rechtecke testen Ein achsenparalleles Rechteck in der Ebenen kann repräsentiert werden durch die Angabe von 4 Gleitkommazahlen. Die ersten beiden werden interpretiert als die x–y–Koordinaten der linken unteren Ecke, die beiden anderen als Koordinaten der rechten oberen Ecke. Schreiben Sie ein Haskell–Skript Rectangle.hs oder Rectangle.lhs, das mindestens die Definitionen folgender Funktionen enthalten soll. Geben Sie jeweils auch die Signatur der Funktionen an. (a) Die Funktion isRectangle überprüft, ob die vier Zahlen tatsächlich ein Rechteck mit nichtleerer Fläche definieren. (b) Die Funktion areaBBox berechnet die Fläche der sogenannten bounding box der zwei Rechtecke, also des kleinsten achsenparallelen Rechtecks, das beide enthält. (c) Die Funktion isContained überprüft von zwei Rechtecken, ob eines davon im anderen völlig enthalten ist. Eine Möglichkeit ist es, auf die Funktion areaBBox zuzugreifen. Wie? Lösung: Die Lösung wurde freundlicherweise bereitgestellt von H. Velkov. Bei der isRectangle-Funktion galt zu beachten, dass das erste Argument die linke untere Ecke des Rechtecks beschreiben soll. type Point = (Float, Float) type Rectangle = (Point, Point) isRectangle :: Point -> Point -> Bool isRectangle (a,b) (c,d) | (c > a) && (d > b) = True | otherwise = False areaBBox :: Rectangle -> Rectangle -> Float areaBBox ((a,b),(c,d)) ((e,f),(g,h)) | (isRectangle (a,b) (c,d) == False ) || (isRectangle (e,f) (g,h) == False ) = error "Keine richtigen Rechtecken vorhanden" | otherwise = (maximum [c,g] - minimum [a,e]) * (maximum [d,h] - minimum [b,f]) {- Solange wir richtige Rechtecken haben, berechnen wir die Flaeche als Produkt des maximalen horizontalen Abstandes zwischen den Ecken und des maximalen vertikalen Abstandes. Diese Maxima werden jeweils von einem Paar bestehend aus rechter oberer Ecke und linker unterer Ecke realisiert-} isContained :: Rectangle -> Rectangle -> Bool isContained ((a,b),(c,d)) ((e,f),(g,h)) | (areaBBox ((a,b),(c,d)) ((e,f),(g,h)) == (c-a)*(d-b)) || (areaBBox ((a,b),(c,d)) ((e,f),(g,h)) == (g-e)*(h-f)) = True | otherwise = False {- Wenn die Fläche der bounding box der zwei Rechtecke gleich der Flaeche von einem der beiden ist, dann ist das eine in dem anderen enthalten-}