Listen in Haskell: Primitive Rekursion über Listen • Listen . . . Zusammenfassung beliebig vieler Elemente vom selben Typ • auch ‘tail recursion’ genannt • Darstellung des Listentyp: [<typ>], z.B. • Definition durch – Angabe des Ausgangswerts für [] und – Angabe, wie von Wert für xs auf Wert von (x:xs) übergegangen wird [Int], [Char], [[Int]], [(Name, Matrnr)], ... • Listen werden – sofern ungleich der leeren Liste [] - durch Anwendung des Konstruktors ‘:’ in eindeutiger Weise ausgehend von [] aufgebaut • Beispiel: length [] = 0 length (x:xs) = 1 + length xs • Beispiel: [4, 2, 3] == 4:2:3:[] == 4:(2:(3:[])) • ‘:’ ist rechts-assoziativ, d.h. x:y:zs = x:(y:zs) c Prof. Dr. D. Rösner; erstellt: 5. April 2007 Sommer 2007, Programmierparadigmen (PGP), 45 Primitive Rekursion über Listen c Prof. Dr. D. Rösner; erstellt: 5. April 2007 Sommer 2007, Programmierparadigmen (PGP), 46 Rekursion über Listen cont. Beachte: • Beispiel: Summe der Werte der Listenelemente • length ist polymorph, d.h. auf Listen unterschiedlichen Typs anwendbar: length :: [a] -> Int • ’wildcard’ in der zweiten Gleichung der Definition möglich, d.h. length ( :xs) = 1 + length xs sum :: [Int] -> Int sum [] = 0 sum (x:xs) = x + sum xs • Frage: sum [2, 4 .. 11] ֒→ . . . ? • length ist wie viele andere Funktionen auf Listen im sog. StandardPrelude von Haskell bereits vordefiniert • sum ist vordefiniert und polymorph Prelude> :t sum sum :: Num a => [a] -> a c Prof. Dr. D. Rösner; erstellt: 5. April 2007 Sommer 2007, Programmierparadigmen (PGP), 47 c Prof. Dr. D. Rösner; erstellt: 5. April 2007 Sommer 2007, Programmierparadigmen (PGP), 48 Rekursion über Listen cont. Der Typ String Beispiel: Sortieren mit Insertion-Sort • Spezialfall: Liste aus Zeichen, d.h. type String = [Char] iSort :: [Int] -> [Int] • alle polymorphen Listenfunktionen können für String benutzt werden iSort [] iSort (x:xs) = [] = ins x (iSort xs) • Ausgabe mit putStr putStr :: String -> IO () ins :: Int -> [Int] -> [Int] ins ins | | • Wechsel zwischen Strings und Werten: show (2 + 3) ==> "5" x [] = [x] x (y:ys) x<= y = x:(y:ys) otherwise = y: ins x ys c Prof. Dr. D. Rösner; erstellt: 5. April 2007 Sommer 2007, Programmierparadigmen (PGP), • umgekehrt: (read "True") :: Bool ==> True 49 c Prof. Dr. D. Rösner; erstellt: 5. April 2007 Sommer 2007, Programmierparadigmen (PGP), 50 Darstellung von Listen Darstellung von Listen • für Listen von Zahlen, Zeichen und anderen Aufzählungstypen gibt es Kurzschreibweisen • Variante: die ‘Differenz’ zwischen dem zweiten und dem ersten Element ergibt die ‘Schrittweite’ • [n .. m] Kurzform für [n,n+1,...,m] (falls m kleiner als n ist Liste leer) • Beispiele: [3,5 .. 14] [0.0,0.4 .. 2.0] [’f’,’h’ .. ’q’] • Beispiele: [3 .. 9] [1.2 .. 4.1] [’f’ .. ’q’] = [3,5,7,9,11,13] = [0.0,0.4,0.8,1.2,1.6,2.0] = "fhjlnp" == [3,4,5,6,7,8,9] == [1.2,2.2,3.2] == "fghijklmnopq" c Prof. Dr. D. Rösner; erstellt: 5. April 2007 Sommer 2007, Programmierparadigmen (PGP), 51 c Prof. Dr. D. Rösner; erstellt: 5. April 2007 Sommer 2007, Programmierparadigmen (PGP), 52 Listenkomprehension Listenkomprehension cont.: Beispiele (vgl. [S.Thompson, 1999, pp.79]) • Vorbild: math. Notation für Mengen • Beispiel: Teiler(n) = {i∈Nk i≤n, i Teiler von n} • Sei ex die Liste [2,4,7] • in Haskell: teiler :: Int -> [Int] teiler n = [ i | i<-[1..n], mod n i == 0] • [ 2*n | n<-ex] ֒→ [4,8,14] • lies: ‘Nimm alle 2*n für n aus der Liste ex’ – Liste [1..n] wirkt als Generator – Test mod n i == 0 wählt Elemente aus • zur Veranschaulichung: Auswertung tabellarisch n 2*n • mehrere Tests in Form boolescher Ausdrücke möglich c Prof. Dr. D. Rösner; erstellt: 5. April 2007 Sommer 2007, Programmierparadigmen (PGP), 53 = = 2 4 4 8 7 14 c Prof. Dr. D. Rösner; erstellt: 5. April 2007 Sommer 2007, Programmierparadigmen (PGP), Listenkomprehension cont.: Beispiele 54 Listenkomprehension cont.: Beispiele (vgl. [S.Thompson, 1999, pp.79]) (vgl. [S.Thompson, 1999, pp.79]) • Sei isEven definiert: • links von <- können nicht nur Variable, sondern auch Muster (pattern) stehen isEven :: Int -> Bool isEven n = (n ‘mod‘ 2 == 0) • Beispiel: addPairs :: [(Int,Int)] -> [Int] addPairs pairList = [ n+m | (n,m) <- pairList] • [ isEven n | n<-ex] ֒→ [True, True, False] • Veranschaulichung mit Tabelle: • mehrere Tests möglich [ n+m n m n+m • [ 2*n | n<-ex, isEven n, n>3] c Prof. Dr. D. Rösner; erstellt: 5. April 2007 Sommer 2007, Programmierparadigmen (PGP), 55 | (n,m) <- [(2,3),(2,1),(7,8)]] = 2 2 7 = 3 1 8 = 5 3 15 c Prof. Dr. D. Rösner; erstellt: 5. April 2007 Sommer 2007, Programmierparadigmen (PGP), 56 Listenkomprehension cont. Listenkomprehension cont.: (vgl. [S.Thompson, 1999, pp.79]) • Syntax: allgemeine Form ist [ e | q1, ... qk ] • zusätzlicher Test: • dabei ist jeder der Qualifikatoren qi • nur geordnete Paare addieren addOrdPairs :: [(Int,Int)] -> [Int] addOrdPairs pairList = [ n+m | (n,m) <- pairList, n < m] • wichtig: ein Ausdruck lExp bzw. bExp in qi kann auf die in q1 bis qi−1 benutzten Variablen verweisen • Frage: addOrdPairs [(2,3),(2,1),(7,8)] ֒→ . . . ? c Prof. Dr. D. Rösner; erstellt: 5. April 2007 Sommer 2007, Programmierparadigmen (PGP), – entweder ein Generator der Form p <- lExp mit p Muster und lExp Ausdruck vom Listentyp – oder ein Test, d.h. boolescher Ausdruck bExp 57 Listenkomprehension cont. c Prof. Dr. D. Rösner; erstellt: 5. April 2007 Sommer 2007, Programmierparadigmen (PGP), Listenkomprehension cont.: (vgl. [S.Thompson, 1999, 17.3]) • pythagoräische Tripel: für welche Tripel (x, y, z) ganzer Zahlen gilt: • mit mehreren Generatoren können Elemente aus zwei oder mehr Listen kombiniert werden x2 + y2 = z2 ? • als Listenkomprehension: • Beispiel: pyTriple n = [(x,y,z)| x<-[2 .. n], y<-[x+1 .. n], z<-[y+1 .. n], x*x+y*y==z*z] pairs :: [a] -> [b] -> [(a,b)] pairs xs ys = [ (x,y) | x<-xs , y<-ys ] • Frage: pyTriple 100 ֒→ ... ? pairs [1,2,3] [4,5] ֒→ [(1,4),(1,5),(2,4),(2,5),(3,4),(3,5)] c Prof. Dr. D. Rösner; erstellt: 5. April 2007 Sommer 2007, Programmierparadigmen (PGP), 58 59 c Prof. Dr. D. Rösner; erstellt: 5. April 2007 Sommer 2007, Programmierparadigmen (PGP), 60