Funktionale Programmierung ALP I Funktionale Programmierung Typ-Klassen und Algebraische Datentypen SS 2013 Prof. Dr. Margarita Esponda Prof. Dr. Margarita Esponda Funktionale Programmierung Funktionen höherer Ordnung Anwendungsbeispiel der zipWith-Funktion: Skalar-Produkt von zwei Vektoren v1 . v2 v1 = (x1, x2, .. , xn) v2 = (y1, y2, .. , yn) v1 . v2 = x1. y1 + x2 . y2 + .. + xn. yn skalarProd ::[Int] -> [Int] -> Int skalarProd xs ys Prof. Dr. Margarita Esponda = foldl (+) 0 (zipWith (*) xs ys) Funktionale Programmierung Funktionen höherer Ordnung Folgende Funktion berechnet die Fibonacci-Zahlen in linearer Zeit O(n) fibs :: [Integer] fibs = 0 : 1 : zipWith (+) fibs (tail fibs) fibs tail fibs zipWith (+) 0:1:1:2:3:5:8:... 1:1:2:3:5:... 1:2:3:5:8:... Anwendungsbeispiel: take 40 fibs Prof. Dr. Margarita Esponda Funktionale Programmierung Funktionen höherer Ordnung Funktionskomposition f A B g g C °f (.) :: (b → c) → (a → b) → (a → c) (.) Beispiel: g f x = (g (f x)) ungerade :: Integer -> Bool ungerade = not . gerade Prof. Dr. Margarita Esponda Die O-Notation Funktionen höherer Ordnung Standardfunktion: iterate :: (a -> a) -> a -> [a] iterate f x = x : iterate f ( f x) Die iterate-Funktion produziert eine unendliche Liste [x, f(x), f(f(x)), f(f(f(x))), … ] Anwendungsbeispiel: iterate (+1) 1 ⇒ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10,..... ALP I: Margarita Esponda, 8. Vorlesung, 19.11.2012 5 Beispiel Welches ist die längste Zeichenfolge, die sich wiederholt? aabcfdesababcdferfcsdeaedabcfdesabeda aabcfdesababcdferfcsdeaedabcfdesabeda LRS-Algorithmus ALP I: Margarita Esponda, 8. Vorlesung, 19.11.2012 6 Beispiel Anwendungen - Linguistik - Bioinformatik (DNA-Analyse) - Datenkompression - Untersuchung von Plagiaten - Antiviren-Software - Musik-Analyse - usw. ALP I: Margarita Esponda, 8. Vorlesung, 19.11.2012 7 Die O-Notation Lösung mit Brute-Force aabcfdesababcdferfcsdeaedabcfdesabeda i j Für alle Startpositionen (i, j) müssen wir das längste Präfix finden. Anzahl der i, j Kombinationen = (n-1) + (n-2) + … + 2 + 1 = O(n2) ALP I: Margarita Esponda, 8. Vorlesung, 19.11.2012 8 Die O-Notation Lösung mit Sortieralgorithmen aacfdebdabcfdebeda acfdebdabcfdebeda cfdebdabcfdebeda fdebdabcfdebeda debdabcfdebeda ebdabcfdebeda bdabcfdebeda dabcfdebeda abcfdebeda bcfdebeda cfdebeda fdebeda debeda ebeda beda eda da a ALP I: Margarita Esponda, 8. Vorlesung, 19.11.2012 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 [ "a a c f d e b d a b c f d e b e d a", "a c f d e b d a b c f d e b e d a", "c f d e b d a b c f d e b e d a", "f d e b d a b c f d e b e d a", "d e b d a b c f d e b e d a", "e b d a b c f d e b e d a", "b d a b c f d e b e d a", "d a b c f d e b e d a", "a b c f d e b e d a", "b c f d e b e d a", "c f d e b e d a", "f d e b e d a", "d e b e d a", "e b e d a", "b e d a", Suffixe oder Startpositionen "e d a", innerhalb der gesamten "d a", Zeichenketten "a"] 9 Die O-Notation Lösung mit Sortieralgorithmen a aacfdebd abcfdebe acfdebda bcfdebed bdabcfde beda cfdebeda cfdebdab da dabcfdeb debdabcf debeda ebdabcfd ebeda eda fdebeda fdebdabc a d b a b bcfdebeda a cfdebeda eda cfdebeda eda debeda ebeda fdebeda ALP I: Margarita Esponda, 8. Vorlesung, 19.11.2012 Die Suffixe werden sortiert 17 0 8 1 9 6 14 10 2 16 7 4 12 5 13 15 11 3 10 Die O-Notation Lösung mit Sortieralgorithmen 17 0 8 1 9 6 14 10 2 16 7 4 12 5 13 15 11 3 a aacfdebd abcfdebe acfdebda bcfdebed bdabcfde beda cfdebeda cfdebdab da dabcfdeb debdabcf debeda ebdabcfd ebeda eda fdebeda fdebdabc a d b a b bcfdebeda a cfdebeda eda Die Präfix-Länge jeder zwei benachbarten Suffixe werden verglichen und das längste cfdebeda Präfix gesucht. eda debeda ebeda LRS-Algorithmus fdebeda ALP I: Margarita Esponda, 8. Vorlesung, 19.11.2012 11 Funktionale Programmierung Überladung von Datentypen Funktionen sollen oft auf verschiedene Datentypen anwendbar sein, aber nicht auf beliebige Datentypen. Beispiel: Die (+) Funktion oder die anderen arithmetischen Operationen sollen auf die Datentypen Int und Double anwendbar sein, aber nicht auf andere Datentypen. 1+2 2.5 + 3.4 Das wird gelöst, indem Typ-Klassen definiert werden. Prof. Dr. Margarita Esponda Funktionale Programmierung Typ-Klassen Mit Typ-Klassen lassen sich in Haskell Typen zusammenfassen, die ähnliche Operationen unterstützen. Variabler Datentyp Beispiel: (+) :: Num a => a -> a -> a Klassenname Die Typ-Variable a kann alle Instanzen der Num-Typklasse annehmen. Die Funktion wird dann für alle Datentypen, die eine Instanz der NumKlasse sind, definiert. Prof. Dr. Margarita Esponda Funktionale Programmierung Definition von Typ-Klassen Vordefinierte Typklassen: Beispiel: class Eq a where (==) :: a - > a -> Bool instance Eq Int where (==) = intEq -- intEq ist die primitive Funktion, die zwei ganze Zahlen auf Gleichheit testet. Prof. Dr. Margarita Esponda Funktionale Programmierung Definition von eigenen Typ-Klassen Eine Typ-Klasse deklariert eine Familie von Funktionen, die für verschiedene Typen unterschiedlich definiert sein können. Allgemeine Syntax: class C a where f1 :: t1 f2 :: t2 … fn :: tn Prof. Dr. Margarita Esponda Typ-Variable Die Typen ti müssen die Typ-Variable a enthalten Funktionale Programmierung Typ-Klassen in Haskell Eine Typ-Klasse ist eine Sammlung von Typen, auf denen eine in der Typ-Klasse festgelegte Menge von Funktionen definiert ist. Die Typ-Klasse Num stellt z. B. die Sammlung der numerischen Datentypen Int, Integer, Float, Double usw. dar, auf denen die Funktionen (+), (*), usw. definiert sind. Prof. Dr. Margarita Esponda Funktionale Programmierung Typ-Klassen in Haskell Die vordefinierte Num-Typ-Klasse sieht vereinfacht so aus: class Num a where (+) :: a -> a -> a (-) :: a -> a -> a (*) :: a -> a -> a negate :: a -> a abs :: a -> a signum :: a -> a ... Typ-Klassen schreiben eine Schnittstelle vor. Prof. Dr. Margarita Esponda Funktionale Programmierung Typ-Klassen in Haskell Alle Typen, die Instanzen von Ord sein sollen, müssen die vorgeschriebenen Vergleichsoperationen implementieren. class Ord a where (<) :: a -> a -> Bool (<=) :: a -> a -> (>) :: a -> a -> Bool (>=) :: a -> a -> Bool max :: a -> a -> a min :: a -> a -> a … Prof. Dr. Margarita Esponda Bool Funktionale Programmierung Eigene Datentypen definieren Typ-Synonyme Ein vorhandener Datentyp wird umbenannt Algebraische Datentypen Neue Datentypen werden definiert mit Hilfe von sogenannten Typ-Konstruktoren. data Prof. Dr. Margarita Esponda Typ-Name = K1 | K2 | … | Kn Funktionale Programmierung Algebraische Datentypen Allgemeine Form: data T a1 …ak = K1 t11 … t1m 1 | K2 t21 … t2m 2 |… | Kn tn1 … tnm n Die Ki sind Konstruktoren und die ai sind die TypParameter des neuen Datentyps T. Prof. Dr. Margarita Esponda Funktionale Programmierung Algebraische Datentypen Beispiele: einfache Aufzählungen data Bool = True | False data Move = Left | Right | Up | Down type Position = (Int, Int) Funktionsbeispiel: move move move move move Prof. Dr. Margarita Esponda :: Move -> Position -> Position Left (x,y) = (x-1,y) Right (x,y) = (x+1,y) Up (x,y) = (x,y+1) Down (x,y) = (x,y-1) Funktionale Programmierung Algebraische Datentypen Beispiel: data Weekday = Mo | Tu | We | Th | Fr | Sa | Su isWeekend :: Weekday -> Bool isWeekend Sa = True isWeekend Su = True isWeekend _ = False Prof. Dr. Margarita Esponda Funktionale Programmierung Algebraische Datentypen Beispiel: data Weekday = Mo | Tu | We | Th | Fr | Sa | Su Mo == Mo => No instance for (Eq Weekday) arising from a use of `==' at <interactive>:1:0-5 Possible fix: add an instance declaration for (Eq Weekday) Wir brauchen eine eigene Gleichheits-Operation 1. Lösung equal :: Weekday -> Weekday -> Bool equal Mo Mo = True equal Tu Tu = True ... equal _ _ = False instance Eq Weekday where x == y = equal x y Prof. Dr. Margarita Esponda Funktionale Programmierung Algebraische Datentypen 2. Lösung data Weekday = Mo | Tu | We | Th | Fr | Sa | Su deriving (Eq, Ord, Show) Instanzen dieser Klassen werden automatisch aus der Typdefinition abgeleitet. Eq Gleichheit und Ungleichheit lässt sich durch Mustervergleich ableiten Ord verwendet die Reihenfolge der Konstruktoren in der Typdefinition Mo < Tu < .. < Su Show Die Namen der Konstruktoren werden in Zeichenketten verwandelt Prof. Dr. Margarita Esponda Funktionale Programmierung Algebraische Datentypen data Weekday = Mo | Tu | We | Th | Fr | Sa | Su deriving (Eq, Ord, Show, Enum) Damit haben wir automatisch alle Vergleichsoperationen, eine show-Funktion für die Ausgabe von Ausdrücken und AufzählungsFunktionen wie succ, pred, fromEnum usw. Wir können sogar Listengeneratoren oder Sequenzlisten verwenden! isWorkday :: Weekday -> Bool isWorkday day = elem day [Mo .. Fr] Prof. Dr. Margarita Esponda Funktionale Programmierung Algebraische Datentypen Typ-Konstruktoren mit Typen als Argumente Beispiel: data Temperatur = Celsius Double | Fahrenheit Double | Kelvin Double deriving Show Die Show-Funktion wird abgeleitet celsius2Kelvin :: Temperatur -> Temperatur celsius2Kelvin (Celsius cel) = Kelvin (cel + 273.16) fahrenheit2Celsius :: Temperatur -> Temperatur fahrenheit2Celsius (Fahrenheit fah) = Celsius ((fah-32)*5/9) Prof. Dr. Margarita Esponda Die O-Notation Algebraische Datentypen data Bit = On | Off deriving (Show) instance Eq Bit where (==) On On = True (==) Off Off = True (==) On Off = False (==) Off On = False ALP I: Margarita Esponda, 8. Vorlesung, 19.11.2012 27 Funktionale Programmierung Algebraische Datentypen type Point = (Double, Double) type Side = Double type Center = Point type Radius = Double type Vertex = (Double, Double) data Shape = Circ Center Radius | Rect Point Point | CPoly [Vertex] deriving (Eq, Show) Prof. Dr. Margarita Esponda Funktionale Programmierung Algebraische Datentypen area :: Shape-> Double area (Circ _ r) = pi*r*r area (Rect (x1, y1) (x2, y2)) = abs ((x2-x1) * (y2-y1)) area (CPoly ps) | length ps < 3 = 0 area (CPoly (p1:p2:p3:ps)) = triangleArea p1 p2 p3 + area (CPoly (p1:p3:ps)) triangleArea :: Vertex -> Vertex -> Vertex -> Double triangleArea (x1,y1) (x2,y2) (x3,y3) = abs ((x2-x1)*(y3-y1) - (x3-x1)*(y2-y1)) / 2 Prof. Dr. Margarita Esponda Die O-Notation Algebraische Datentypen myDiv :: Float -> Float -> Float myDiv x 0 = error "Division by zero" Wir möchten aber keine Fehlermeldung myDiv x y = x / y data Maybe a = Nothing | Just a safeDiv :: Float -> Float -> Maybe Float safeDiv x 0 = Nothing safeDiv x y = Just (x / y) ALP I: Margarita Esponda, 8. Vorlesung, 19.11.2012 safeIDiv :: Int -> Int -> Maybe Int safeIDiv n m = if m == 0 then Nothing else Just (n `div` m) 30