260 likes | 491 Views
Listenkomprehension und Typenklassen anhand von Haskell. Proseminar an der TU München Martin Levihn 05.07.2007. Gliederung. Listenkomprehension Einleitung und Motivation Syntax Beispiele und Arbeitsweise mit einem Generator Beispiele und Arbeitsweise mit mehreren Generatoren
E N D
Listenkomprehension und Typenklassen anhand von Haskell Proseminar an der TU München Martin Levihn 05.07.2007
Gliederung • Listenkomprehension • Einleitung und Motivation • Syntax • Beispiele und Arbeitsweise mit einem Generator • Beispiele und Arbeitsweise mit mehreren Generatoren • Übersetzung von Listenkomprehension • Typklassen • Begriffserklärung und Einleitung • Deklarationen • Klassendeklaration • Kontext eines Typs • Instanzen deklarieren • Abgeleitete Klassen • Praktische Anwendung • Vergleich zu OOP
Listenkomprehension • Listenkomprehension ähnlich Mengenbeschreibung in der Mathematik • Erstelle Liste als Beschreibung in Bezug auf eine andere Liste • [ x | x <- xs] • „Erstelle die Liste aus allen x, wobei x Element der Liste xs“
Syntax • Allgemein [ Ausdruck | q1, q2, … , qk] • Ausdruck kann beliebige Funktion sein • Qualifikatoren q1 bis qk können sein: • Generator p <- xs, wobei p Variable / Variablen Tupel und xs Listenausdruck • Test, boolscher Ausdruck zum „Auswählen“
Einfache Beispiele (ein Generator) • Verdoppeln jedes Elementes in einer Int Liste double :: [Int] -> [Int] double xs = [ 2*x | x <- xs] Aufruf double [2,3,4] [4,6,8] • Nur die geraden Werte aus einer Int Liste auswählen gerade :: [Int ] -> [ Int] gerade xs = [x | x <- xs, mod x 2 == 0 ] Aufruf gerade [2,3,4] [2,4]
Einfache Beispiele (ein Generator) • map :: (a -> b ) -> [a] -> [b] Funktion rekursiv map f [] = [] map f (x:xs) = f x : map f xs • mit Listkomprehension map f xs = [ f x | x <- xs] • filter :: (a -> Bool) -> [a] -> [a] Funktion rekursiv filter p [] = [] filter p (x:xs) = | p x = x : filter p xs |otherwise = filter p xs • mit Listkomprehension filter p xs = [ x | x <- xs, p x]
Arbeitsweise allgemein (ein Generator) • Format: [f x | x <- xs, p1 x, p2 x , … , pk x] 1) xs wird von links nach rechts durchlaufen 2) ist p1 für x erfüllt, teste p2 … pk a) sind alle „erfüllt“, füge x in Ergebnisliste b) sonst lasse x unberücksichtigt 3) fahre mit nächstem Element fort
Einfache Beispiele (mehrere Generatoren) • Bilde Tupel (x, y) mit x aus xs und y aus ys pairs :: [a] -> [b] -> [(a, b)] pairsxsys= [ (x,y)| x <- xs, y <- ys] Aufruf pairs[1,2,3] [4,5] [(1,4), (1,5), (2,4), (2,5), (3,4), (3,5)] • Bilde pythagoräische Triple pyTriple n :: Int -> [(Int,Int, Int)] pyTriple n = [ (x, y, z) | x <- [2 .. n], y<-[x .. n], z<-[y .. n], x*x+y*y == z*z] AufrufpyTrible 15 [(3,4,5),(5,12,13),(6,8,10),(9,12,15)]
Arbeitsweise Allgemein (mehrere Generatoren) • Format: [ f x | x <- xs, y <- ys , ... z <- zs, p1 , ... pk] • erste Element von xs wird x zugewiesen • für dieses feste x wird das erste y von ys zugewiesen usw. • für diese festen Werte wird z nun von links nach rechts durchlaufen und die Tests werden duchgeführt • es wird der Wert vor dem z erhöht usw. anschaulich: • for (int i1=0; i1<length(xs); i1++){ • for (int i2=0; g1<length(ys); i2++){ • …. • for(int in=0; in<length(zs); in++){ • ….}…}}
Übersetzung von Listenkomprehension • [e | True ] [e] • [e | t, Q] if t then [e | Q] else [] • [e | p<- xs, Q] concatMapfqxs wherefq p = [e | Q] concatMap:: (a -> [b]) -> [a] -> [b] concatMap f [] = [] concatMap f (x:xs) = f x ++ concatMap f xs
Übersetzung von Listenkomprehension • pyTriple n = [ (x, y, z) | x <- [2 .. n], y<-[x .. n], z<-[y .. n], x*x+y*y == z*z] • pyTriple n = concatMap f1 [2 .. n] where f1 x = concatMap f2 [x .. n] where f2 y = concatMap f3 [y .. n] where f3 z = if (x*x + y*y == z*z) then [(x,y,z)] else []
Typenklassen • Polymorphismus • ist, wenn eine Funktion unabhängig von dem Datentyp arbeitet: length :: [a] -> Int length []= 0 length (_:xs) = 1 + length xs • Ad-hoc Polymorphismus • im Sinne von Überladen. Es also für gleichen Operator unterschiedliche Implementierungen gibt (Beispiel + Operator in Java) • Hindley-Milner Typsystem • Typinferenzen werden vom System automatisch erkannt • -> typisiertes Lambda-Kalkühl
Typklassen • Operationen nur auf Typen mit einer gewissen Semantik • Beispiel: elem :: a -> [a] -> Bool elem x [] = False elem x (y:ys) = (x==y) || (elem x ys) • nur möglich wenn == für a definiert • Mittelweg zwischen Polymorphismus und Monomorphismus
Klassendeklaration classEq a where (==) :: a -> a -> Bool • Name der Klasse (Eq) • Signatur der Klasse („fordert“ das (==) implementiert ist) class Name a where ...verlangte Singnatur...
Kontext eines Typs alleQual :: Int -> Int -> Int -> Bool allEqual m n p = (m==n) && (n==p) • keine Beschränkung auf Int sondern auf ==, Verallgemeinerung: alleQual :: Eq a => a -> a -> a -> Bool allEqual m n p = (m==n) && (n==p) • Bereich vor dem => heißt Kontext • „Wenn der Typ a in der Kasse Eq ist, dann hat allEqual den Typ a -> a -> a -> Bool.“
Kontext eines Typs • Liste aus Tupeln soll auf dem ersten Wert sortiert werden und die zweiten Werte sollen ausgegeben werden. • HakellPrelude bietet Klasse Ord, definiert Vergleichsoperatoren, • sowie Visible: class Visible a where toString :: a -> String size :: a -> Int
Kontext eines Typs • geforderte Funktionalität durch Kontext sichergestellt: bSort :: (Ord a, Visible b) => [(a, b)] -> a -> String • Verletzender constraints : nachfolger :: Int -> Int nachfolger = (+1) Aufruf allEqualnachfolgernachfolgernachfolger ERROR: Int -> Int is not an instance of class “Eq”
Instanz einer Klasse • Um einen Typ als Instanz einer Typklasse zu deklarieren, müssen die in der Signatur geforderten Funktionen implementiert werden • Beispiel Bool als Instanz von Eq deklarieren: instanceEqBoolwhere True==True = True False==False = True _ == _ = False
Instanz einer Klasse • Gleichheitstest auf Listen definieren instance Eq[a] where [] == [] = True x:xs == y:ys = x==y && xs==ys _ == _ = False • Ist == definiert?
Instanz einer Klasse • Gleichheitstest nur auf Liste definiert, deren Elemente selbst Instanzen von Eq sind instance Eq a => Eq [a] where [] == [] = True x:xs == y:ys = x==y && xs==ys _ == _ = False • können == als gegeben voraussetzen
Abgeleitete Klassen • Eine Art Vererbung class Eq a => Ord a where (<), (<=), (>), (>=) :: a -> a -> Bool max, min :: a -> a -> Bool compare :: a -> a -> Ordering x <= y = (x < y || x==y) x > y = y < x • Eine Abgeleitete Klasse kann ebenfalls mehrere Basisklassen haben class (Num a, Ord a) => Real a where ...
Praktische Anwendung • data Tag = So | Mo | Di | Mi | Do | Fr | Sa • Um Vergleiche zu machen, deklarieren wir Tag als Instanz von Eq und Ord • Führen Vergleich auf Vergleich von Ints zurück: classEnum a where fromEnum :: a -> Int toEnum :: Int -> a instanceEnum Tag where fromEnum So = 0 fromEnum Mo = 1 fromEnum Di = 2 ... • toEnum analog
Praktische Anwendung instanceEq Tag where (x==y) = (toEnum x == toEnum y) instanceOrd Tag where (x<y) = (toEnum x < toEnum y) • Da dies ein häufiges Vorgehen ist, bietet Haskell dazu die Kurzschreibweise: data Tag = So | Mo | Di | Mi | Do | Fr | Sa deriving (Enum, Eq, Ord) • Instanzen werden automatisch erstellt
Vergleich zu OOP • Gemeinsamkeiten: • Um Instanz zu werden, sind Implementierungen nötig Interfaces in Java oder Basisklassen in C++ • in C++ Default-Implementierungen • Selbstdefinierte Typen können auf Standardoperationen implementiert werden
Vergleich zu OOP • Unterschiede • starke Trennung von Typdeklarationen, Typklassen- und Instanzdeklarationen • Haskell: Klasse ist Sammlung von Typen • C++ : Typen und Klassen synonym • kein Zustand eines Objekts möglich • Kein dynamicbinding möglich • In OOP möglich • show :: ShowType -> String • Bools , Chars wären sub-classes, • [True, 'n', False] ::[ShowType] • In Java sind die implementierten Interfaces/Klassen bei der Klassendefinition anzugeben, bei Haskell späteres Hinzufügen möglich
Literatur • [1] Simon Thompson, 1999. The Craft of Functional Programming, second edition, Addison Wesley Longman, Great Britain • [2] Richard Bird, 1998. Introduction to Functional Programming using Haskell, second edition, Prentice Hallo, Great Britain • [3] The Haskell 98 Report, December 2002, http://www.haskell.org/onlinereport/exps.html#list-comprehensions • [4] D. Rösner, 2007. Einführung in Programmierparadigmen, Univ. Magedburg, http://wdok.cs.uni-magdeburg.de/studium-und-lehre/ lehrveranstaltungen/sommer2007/pgp/slides • [5] Uwe Schmidt, 2002. Abstrakte Datentypen und das Typsystem von Haskell, FH Wedel, http://www.fh-wedel.de/~si/seminare/ss02/Ausarbeitung/2. types/typhas3.html • [6] Peter Padawitz, 2005. Übersetzerbau, Univ. Dortmund http://fldit-www.cs.uni-dortmund.de/~peter/Kapitel1-2.pdf