26.10.2009 ALP I Einführung in Haskell Teil II WS 2009/2010 Prof. Dr. Margarita Esponda 1 26.10.2009 Zusammengesetzte Datentypen Tupel List String 2 26.10.2009 Zusammengesetzte Datentypen Tupel-Datentyp Ein Tupel ist eine Ansammlung von zwei oder mehreren Daten, die unterschiedliche Datentypen besitzen können. Mit Hilfe von Tupel können zusammengehörige Daten als Einheit behandelt werden. Studierende Beispiele: ( "Peter" , "Meyer", 439990 ) ( 2.5, 3.0 ) :: ( String, String, Int ) :: ( Double, Double ) Punkt 3 26.10.2009 Tupel-Typ Ein Tupel-Typ hat folgende allgemeine Form: ( t1 , t2 , … , tn ) mit t1 , t2 , … , tn beliebige Datentypen Funktionsdefinition mit Tupeln: distance (x1,y1) (x2,y2) = sqrt (sumSquares (x1-x2) (y1-y2) ) sumSquares :: Double -> Double -> Double sumSquares x y = squareX + squareY where squareX = x * x squareY = y * y 4 26.10.2009 Typ-Synonyme Typsynonyme werden verwendet, um die Lesbarkeit von Programmen mit Hilfe von aussagekräftigen Typ-Namen zu verbessern. Allgemeine Form: type Typname = ……. Beispiel: type Student = (String, String, Int) 5 26.10.2009 Typ-Synonyme Beispiel: type Complex = (Double, Double) realPart :: Complex -> Double realPart ( real, img ) = real imgPart :: Complex -> Double imgPart ( real, img ) = img sumC :: Complex -> Complex -> Complex sumC (r1,i1) (r2,i2) = (r1+r2, i1+i2) absC :: Complex -> Double absC ( real, img ) = sqrt( real*real + img*img ) 6 26.10.2009 Listen • Listen sind die wichtigsten Datenstrukturen in Funktionalen Programmiersprachen • Listen stellen Sammlungen von Objekten dar, die den gleichen Datentyp besitzen • Listen sind dynamische Datenstrukturen, die mit Hilfe folgender Daten-Konstruktoren erzeugt werden können Symbol Name Bedeutung [] nil leere Liste (:) cons am Anfang anfügen 7 26.10.2009 Listen Listen sind rekursive Strukturen: Eine Liste ist entweder leer [] oder ein konstruierter Wert, der aus einem Listenkopf x und einer Restliste xs besteht. head tail x:xs Der Typ einer Liste, die Elemente des Typs t enthält, wird mit [t] bezeichnet. 8 26.10.2009 Listen Beispiele: Datentyp der Liste [1, 2, 3] :: [Integer] 1: [0,3,7] :: [Integer] [ [0.3, 0.0], [] ] :: [[Double]] 'a' : "Hello" :: [Char] [( 3, 0 ), ( 2, 1)] :: [ (Integer, Integer) ] [ True, True, False ] :: [ Bool ] Allgemeine Syntax: [ e1, e2, e3, … ,en ] Syntaktische Abkürzung: e1:[e2:[e3: … :en:[]]] e1:e2: … :en:[] 9 26.10.2009 Listen summe :: [ Integer ] -> Integer summe ls = if ls == [] then 0 else ( kopf ls ) + summe (rumpf ls ) kopf :: [ Integer ] -> Integer kopf (x:xs) = x kopf [] = error "ERROR: empty list" rumpf :: [ Integer ] -> [ Integer ] rumpf (x:xs) = xs rumpf [] = error "ERROR: empty list“ 10 26.10.2009 Funktionsdefinitionen mit Listen sumList :: [Integer] -> Integer sumList [] = 0 sumList (x:xs) = x + sumList xs multList :: [Integer] -> Integer multList [x] = x multList (x:xs) = x * multList xs multList [] = error "the function is not defined for []" laenge :: [Int] -> Int laenge [] = 0 laenge (x:xs) = 1 + laenge xs 11 26.10.2009 Pattern-Matching In Haskell es ist möglich, die erwartete Struktur der Funktionsargumente zu spezifizieren, um mit Hilfe von Pattern-Matching eine Auswahl zwischen verschiedenen Funktionsgleichungen zu definieren. Allgemeine Form: f p11 p12 … p1n = e1 f p21 p22 … p2n = e2 ….. f pk1 pk2 … pkn = ek Die pij Muster werden von oben nach unten und von links nach rechts geprüft. 12 26.10.2009 Einige Funktionen auf Listen Name Typ Beispiel head [a] -> a head [1,2,3] => 1 tail [a] -> [a] tail [1,2,3] => [2,3] length [a] -> Int length [1,2,3] => 3 (++) [a] -> [a] -> [a] [1,2,3] ++ [1,2,3] => [1,2,3,1,2,3] (!!) [a] -> Int -> [a] [1,2,3,4] !! 2 => 3 take Int -> [a] -> [a] take 2 [1,2,3,4] => [1,2] drop Int -> [a] -> [a] drop 2 [1,2,3,4] => [3,4] 13 26.10.2009 Arithmetische Sequenzen Mit Hilfe des .. Operators lassen sich in Haskell sehr elegant Zahlensequenzen erzeugen. [ 1 .. 5 ] => [1,2,3,4,5] [ 0, 5 .. 21] => [ 0, 5, 10, 15, 20 ] [ 10, 8 .. 0 ] => [ 10, 8, 6, 4, 2, 0 ] [ 10 .. 1 ] => [] [ 1 .. ] => unendliche Liste take 5 [2, 0 .. ] => [ 2, 0, -2, -4, -6 ] 14 26.10.2009 Strings Strings sind Listen von Zeichen Type-Synomym type String = [Char] Syntaktische Abkürzung [ 'H' , 'e', 'l', 'l', 'o' ] => "Hello" Haskell ruft implizit am Ende der Auswertung eines Ausdrucks die ShowFunktion an, die aus einem beliebigen Datentyp einen String erzeugt. … 15 26.10.2009 Listen-Generatoren Die Syntax von Listengeneratoren in Haskell ist sehr ähnlich zu dem, was wir für die Definition von Menge in der Mathematik kennen. Mathematik: { x ∈ { 1 .. 20 } | x mod 3 = 0 } Menge aller Zahlen, die genau durch 3 geteilt werden können Haskell: [ x | x <- [1 .. 20], mod x 3 == 0 ] damit gibt man Haskell die Anweisung eine Liste zu bilden aus allen Elementen, die genau durch 3 geteilt werden können: Sollen dabei mehrere Bedingungen erfüllt werden, so müssen diese durch Komma getrennt sein. Im Unterschied zu der mathematischen Definition von Menge können HaskellListen sich wiederholende Elemente beinhalten. … 16 26.10.2009 Currying In Haskell kann eine Funktion, die zwei oder mehr Argumente erwartet, als eine Verschachtelung von Funktionen interpretiert werden, die jeweils nur ein Argument bekommen ( implizites Currying). Beispiel: sum :: Int -> Int -> Int sum x y = x + y Diese Definition ermöglicht eine partielle Anwendung wie z.B. sum 1, die als Ergebnis eine Funktion zurückgibt, die ein zweites Argument erwartet. inc :: Int -> Int inc = (sum 1) . 17 26.10.2009 Korrekte und Effiziente Lösung von Problemen Problem Wesentlicher Teil der Lösung eines Problems. Sehr Kreative Phase Algorithmus Programmierung oder Codierung des Algorithmus in einer bestimmten Programmiersprache. Einfache Phase Programm in einer höheren Programmiersprache 18 26.10.2009 Algorithmen Definition von Algorithmus Ein Algorithmus ist eine präzise, endliche Verarbeitungsvorschrift zur Lösung eines Problems. Ein Algorithmus ist ein Plan zur Lösung eines Problems mit Hilfe einer endlichen Folge eindeutiger, ausführbarer Schritte. Algorithmen sind sprachunabhängig. 19 26.10.2009 Analyse von Algorithmen Korrektheit Wichtigste Eigenschaften bei der Terminierbarkeit Analyse von Algorithmen - Rechenzeit Komplexität - Speicherplatz - Bandbreite oder Datentransfer 20 26.10.2009 Analyse von Algorithmen Rechenzeit Anzahl der durchgeführten Elementaroperationen in Abhängigkeit von der Eingabegröße. Speicherplatz Maximaler Speicherverbrauch während der Ausführung des Algorithmus in Abhängigkeit von der Komplexität der Eingabe. Bandbreite Wie groß ist die erforderliche Datenübertragung? 21 26.10.2009 Analyse von Algorithmen Charakterisierung unserer Daten (Eingabegröße) Rechenzeit oder Bestimmung der abstrakten Operationen (Berechnungsschritte in unserem Algorithmus) Zeitanalyse Eigentliche mathematische Analyse, um eine Funktion in Abhängigkeit zur Eingabegröße zu finden. Komplexitätsanalyse 22 26.10.2009 Multiplikation von zwei komplexen Zahlen i i (a+b ) (c+d ) i i i ac + adi + bci - bd = ac + ad + bc + bd = 2 = ( ac - bd ) + ( ad + bc ) i a, b, c, d Eingabe: 2 Additionen (ac – bd), (ad + bc) Ausgabe: e Eine Multiplikation kostet 1 Euro Eine Summe kostet 1 Cent , fi 4 Multiplikationen Zwei komplexe Zahlen zu multiplizieren kostet 4,02 є 23 26.10.2009 Algorithmus von Gauß i i (a+b ) (c+d ) 2 3 a+b c+d ac bd r4 r5 3 r4 - r5 r3 r3 = r1 r2 = ac + ad + bc + bd r3 – r4 – r5 = ac + ad + bc + bd – ac – bd = ad + bc 5 r3 - r4 - r5 = 1 r1 r2 4 = 2 1 (ac – bd) , (ad + bc) i 3 Multiplikationen 5 Summen Zwei komplexe Zahlen zu multiplizieren kostet 3,05 є 24 26.10.2009 Zwei Lösungen multC :: Complex -> Complex -> Complex multC (a,b) (c,d) = ( a*c - b*d, a*d + b*c ) gaussMultC :: Complex -> Complex -> Complex gaussMultC (a,b) (c,d) = ( r4 - r5, r3 - r4 - r5) where r1 = a+b r2 = c+d r3 = r1*r2 r4 = a*c r5 = b*d 25 26.10.2009 Sieb des Eratosthenes 3. Jahrhundert v. Chr. Das Sieb des Eratosthenes ist ein sehr bekannter Algorithmus, der für ein vorgegebenes N alle Primzahlen findet, die kleiner gleich N sind. Der Algorithmus verwendet ein Feld p aus booleschen Werten, mit dem Ziel, dem Element p[i] den Wert 1 zuzuweisen, falls i eine Primzahl ist, und anderenfalls den Wert 0. Ziel: P P P P P 1 2 3 4 5 6 7 8 9 10 11 0 1 1 0 1 0 1 0 0 0 1 P 26 26.10.2009 Sieb des Eratosthenes Anfang: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 0 1 1 0 1 1 0 1 1 0 1 1 0 1 1 0 1 1 0 1 1 0 1 1 0 1 1 0 1 1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 0 1 1 0 1 0 1 0 0 1 0 1 0 1 0 0 1 0 1 0 1 0 0 1 27 26.10.2009 Sieb des Eratosthenes 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 0 1 1 0 1 0 1 0 0 0 1 0 1 0 0 0 1 0 1 0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 0 1 1 0 1 0 1 0 0 0 1 0 1 0 0 0 1 0 1 0 0 N nicht mehr! 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 0 1 1 0 1 0 1 0 0 0 1 0 1 0 0 0 1 0 1 0 0 nur bis N/2 noch besser ist nur bis 2 N 28 26.10.2009 Listen primzahlen n = sieb [2..n] where sieb [] = [] sieb (p:x) = p:sieb[k | k<-x, k `mod` p>0] primzahlen2 = sieb [2..] where sieb (p:x) = p:sieb[k | k<-x, k `mod` p>0] 29