26
Listenkomprehension und Typenklassen anhand von Haskell Proseminar an der TU München Martin Levihn 05.07.2007

Proseminar an der TU München Martin Levihn 05.07.2007

Embed Size (px)

Citation preview

Page 1: Proseminar an der TU München Martin Levihn 05.07.2007

Listenkomprehension und Typenklassen anhand von Haskell

Proseminar an der TU MünchenMartin Levihn

05.07.2007

Page 2: Proseminar an der TU München Martin Levihn 05.07.2007

GliederungListenkomprehension

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

2

Page 3: Proseminar an der TU München Martin Levihn 05.07.2007

ListenkomprehensionListenkomprehension ä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“

3

Page 4: Proseminar an der TU München Martin Levihn 05.07.2007

SyntaxAllgemein [ 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“

4

Page 5: Proseminar an der TU München Martin Levihn 05.07.2007

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ählengerade :: [Int ] -> [ Int]gerade xs = [x | x <- xs, mod x 2 == 0 ]

Aufruf gerade [2,3,4] [2,4]

5

Page 6: Proseminar an der TU München Martin Levihn 05.07.2007

Einfache Beispiele (ein Generator)map :: (a -> b ) -> [a] -> [b] Funktion rekursiv

map f [] = []map f (x:xs) = f x : map f xs

mit Listkomprehensionmap f xs = [ f x | x <- xs]

filter :: (a -> Bool) -> [a] -> [a] Funktion rekursivfilter p [] = []filter p (x:xs) = | p x = x : filter p xs|otherwise = filter p xs

mit Listkomprehensionfilter p xs = [ x | x <- xs, p x]

6

Page 7: Proseminar an der TU München Martin Levihn 05.07.2007

Arbeitsweise allgemein (ein Generator)Format: [f x | x <- xs, p1 x, p2 x , … , pk x]

1) xs wird von links nach rechts durchlaufen2) ist p1 für x erfüllt, teste p2 … pk

a) sind alle „erfüllt“, füge x in Ergebnislisteb) sonst lasse x unberücksichtigt

3) fahre mit nächstem Element fort

7

Page 8: Proseminar an der TU München Martin Levihn 05.07.2007

Einfache Beispiele (mehrere Generatoren)Bilde Tupel (x, y) mit x aus xs und y aus ys

pairs :: [a] -> [b] -> [(a, b)]pairs xs ys= [ (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]

Aufruf pyTrible 15 [(3,4,5),(5,12,13),(6,8,10),(9,12,15)]

8

Page 9: Proseminar an der TU München Martin Levihn 05.07.2007

Arbeitsweise Allgemein (mehrere Generatoren)Format: [ f x | x <- xs, y <- ys , ... z <- zs, p1 , ... pk]

1) erste Element von xs wird x zugewiesen2) für dieses feste x wird das erste y von ys zugewiesen

usw.3) für diese festen Werte wird z nun von links nach

rechts durchlaufen und die Tests werden duchgeführt4) 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++){ ….}…}}

9

Page 10: Proseminar an der TU München Martin Levihn 05.07.2007

Übersetzung von Listenkomprehension[e | True ] [e][e | t, Q] if t then [e | Q] else [][e | p<- xs, Q] concatMap fq xs where fq p = [e | Q]

concatMap:: (a -> [b]) -> [a] -> [b]concatMap f [] = []concatMap f (x:xs) = f x ++ concatMap f xs

10

Page 11: Proseminar an der TU München Martin Levihn 05.07.2007

Ü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 []

11

Page 12: Proseminar an der TU München Martin Levihn 05.07.2007

TypenklassenPolymorphismus

ist, wenn eine Funktion unabhängig von dem Datentyp arbeitet:length :: [a] -> Intlength []= 0length (_:xs) = 1 + length xs

Ad-hoc Polymorphismusim Sinne von Überladen. Es also für gleichen Operator

unterschiedliche Implementierungen gibt (Beispiel + Operator in Java)

Hindley-Milner TypsystemTypinferenzen werden vom System automatisch erkannt

-> typisiertes Lambda-Kalkühl

12

Page 13: Proseminar an der TU München Martin Levihn 05.07.2007

TypklassenOperationen nur auf Typen mit einer

gewissen SemantikBeispiel:

elem :: a -> [a] -> Boolelem x [] = Falseelem x (y:ys) = (x==y) || (elem x ys)

nur möglich wenn == für a definiertMittelweg zwischen Polymorphismus und

Monomorphismus

13

Page 14: Proseminar an der TU München Martin Levihn 05.07.2007

Klassendeklaration class Eq a where (==) :: a -> a -> Bool

Name der Klasse (Eq)Signatur der Klasse („fordert“ das (==)

implementiert ist)

class Name a where ...verlangte Singnatur...

14

Page 15: Proseminar an der TU München Martin Levihn 05.07.2007

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 -> BoolallEqual 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.“

15

Page 16: Proseminar an der TU München Martin Levihn 05.07.2007

Kontext eines TypsListe aus Tupeln soll auf dem ersten Wert

sortiert werden und die zweiten Werte sollen ausgegeben werden.Hakell Prelude bietet Klasse Ord, definiert

Vergleichsoperatoren,sowie Visible:

class Visible a wheretoString :: a -> Stringsize :: a -> Int

16

Page 17: Proseminar an der TU München Martin Levihn 05.07.2007

Kontext eines Typsgeforderte Funktionalität durch Kontext

sichergestellt:

bSort :: (Ord a, Visible b) => [(a, b)] -> a -> String

Verletzen der constraints : nachfolger :: Int -> Int nachfolger = (+1)

Aufruf allEqual nachfolger nachfolger nachfolger ERROR: Int -> Int is not an instance of class “Eq”

17

Page 18: Proseminar an der TU München Martin Levihn 05.07.2007

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: instance Eq Bool where True==True = True False==False = True _ == _ = False

18

Page 19: Proseminar an der TU München Martin Levihn 05.07.2007

Instanz einer Klasse Gleichheitstest auf Listen definieren

instance Eq [a] where[] == [] = Truex:xs == y:ys = x==y && xs==ys_ == _ = False

Ist == definiert?

19

Page 20: Proseminar an der TU München Martin Levihn 05.07.2007

Instanz einer Klasse Gleichheitstest nur auf Liste definiert,

deren Elemente selbst Instanzen von Eq sind

instance Eq a => Eq [a] where[] == [] = Truex:xs == y:ys = x==y && xs==ys_ == _ = False

können == als gegeben voraussetzen

20

Page 21: Proseminar an der TU München Martin Levihn 05.07.2007

Abgeleitete KlassenEine Art Vererbung

class Eq a => Ord a where(<), (<=), (>), (>=) :: a -> a -> Boolmax, min :: a -> a -> Boolcompare :: a -> a -> Orderingx <= 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...

21

Page 22: Proseminar an der TU München Martin Levihn 05.07.2007

Praktische Anwendungdata Tag = So | Mo | Di | Mi | Do | Fr | SaUm Vergleiche zu machen, deklarieren wir Tag als Instanz

von Eq und OrdFühren Vergleich auf Vergleich von Ints zurück:

class Enum a wherefromEnum :: a -> InttoEnum :: Int -> a

instance Enum Tag wherefromEnum So = 0fromEnum Mo = 1fromEnum Di = 2...

toEnum analog22

Page 23: Proseminar an der TU München Martin Levihn 05.07.2007

Praktische Anwendunginstance Eq Tag where(x==y) = (toEnum x == toEnum y)

instance Ord 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

23

Page 24: Proseminar an der TU München Martin Levihn 05.07.2007

Vergleich zu OOPGemeinsamkeiten:

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

24

Page 25: Proseminar an der TU München Martin Levihn 05.07.2007

Vergleich zu OOPUnterschiede

starke Trennung von Typdeklarationen, Typklassen- und InstanzdeklarationenHaskell: Klasse ist Sammlung von TypenC++ : Typen und Klassen synonym kein Zustand eines Objekts möglich

Kein dynamic binding 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

25

Page 26: Proseminar an der TU München Martin Levihn 05.07.2007

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

26