Programmieren in Haskell. Abstrakte Datentypen

Ähnliche Dokumente
Programmieren in Haskell Abstrakte Datentypen

5. Januar Universität Bielefeld AG Praktische Informatik. Programmieren in Haskell. Stefan Janssen. Abstrakte Datentypen.

Gliederung. Algorithmen und Datenstrukturen I. Binäre Bäume: ADT Heap. inäre Bäume: ADT Heap. Abstrakte Datentypen IV. D. Rösner

Gliederung. Algorithmen und Datenstrukturen Einführung. Abstrakte Datentypen. Abstrakte Datentypen in Haskell. Abstrakte Datentypen (ADT) I

Programmieren in Haskell Programmiermethodik

12. Dynamische Datenstrukturen

Funktionale Programmierung ALP I. Algebraische Datentypen und Abstrakte Datentypen. SS 2013 Prof. Dr. Margarita Esponda. Prof. Dr.

Geheimnisprinzip: (information hiding principle, Parnas 1972)

Abstrakte Datentypen I

- Welche konkreten Invarianten müssen gelten? Berücksichtigen: Invarianten aus Modell und Implem.

2.3 Spezifikation von Abstrakten Datentypen

Abstrakter Datentyp (ADT): Besteht aus einer Menge von Objekten, sowie Operationen, die auf diesen Objekten wirken.

ALP II Dynamische Datenmengen Datenabstraktion

Wiederholung: Zusammenfassung Felder. Algorithmen und Datenstrukturen (für ET/IT) Definition Abstrakter Datentyp. Programm heute

Paradigmen der Programmierung

Programmieren in Haskell Einstieg in Haskell

Programmieren in Haskell

13. Dynamische Datenstrukturen

Programmieren in Haskell

16. Dynamische Datenstrukturen

Programmieren in Haskell

Programmieren in Haskell

Counting - Sort [ [ ] [ [ ] 1. SS 2008 Datenstrukturen und Algorithmen Sortieren in linearer Zeit

Programmierkurs II. Typsynonyme & algebraische Datentypen

Programmierung 1 (Wintersemester 2015/16) Wiederholungstutorium Lösungsblatt 15 (Linearer Speicher, Listen, Bäume)

Übungsblatt 6: Softwareentwicklung I (WS 2006/07)

Abstrakte Datentypen und deren Implementierung in Python

Programmieren in Haskell

11. Elementare Datenstrukturen

Algorithmen und Programmieren 1 Funktionale Programmierung - Musterlösung zur Übungsklausur -

Einführung in die funktionale Programmierung

B2.1 Abstrakte Datentypen

Einführung in Haskell

1 Abstrakte Datentypen

Typklassen. Natascha Widder

Tutoraufgabe 1 (Implementierung eines ADTs):

8 Elementare Datenstrukturen

Graphdurchmusterung, Breiten- und Tiefensuche

Übung Algorithmen und Datenstrukturen

Programmieren in Haskell

Algorithmen und Datenstrukturen (für ET/IT)

Algorithmen und Datenstrukturen I

Algorithmen und Datenstrukturen (für ET/IT)

Spezielle Datenstrukturen

Funktionale Programmierung. ALP I Lambda-Kalkül. Teil III SS Prof. Dr. Margarita Esponda. Prof. Dr. Margarita Esponda

Nachtrag: Vergleich der Implementierungen von Stack

Einführung in die Objektorientierte Programmierung Vorlesung 18: Lineare Datenstrukturen. Sebastian Küpper

Programmieren in Haskell. Stefan Janssen. Strukturelle Rekursion. Universität Bielefeld AG Praktische Informatik. 10.

Stacks, Queues & Bags. Datenstrukturen. Pushdown/Popup Stack. Ferd van Odenhoven. 19. September 2012

Funktionale Programmierung. ALP I Lambda-Kalkül. Teil IVb WS 2012/2013. Prof. Dr. Margarita Esponda. Prof. Dr. Margarita Esponda

Abstrakte Datentypen und Datenstrukturen

ALP II Dynamische Datenmengen Datenabstraktion (Teil 2)

Gliederung. Algorithmen und Datenstrukturen II. Prioritätsgesteuerte Suche. Entwurfstechniken für Algorithmen. Entwurfstechniken für Algorithmen

Programmieren in Haskell

Programmieren in Haskell Felder (Arrays)

Algorithmen und Programmierung

Algorithmen und Programmieren 1 Funktionale Programmierung - Musterlösung zu Übung 9 -

Funktionale Programmierung ALP I. Funktionen höherer Ordnung SS Prof. Dr. Margarita Esponda. Prof. Dr. Margarita Esponda

13 Abstrakte Datentypen

expr :: Expr expr = Mul (Add (Const 3) (Const 4)) (Div (Sub (Const 73) (Const 37)) (Const 6))

How To Understand The Algebraic Structure Of A Program In Python (For Beginners)

Datenstrukturen. Ziele

1. Die rekursive Datenstruktur Liste

Kapitel 3: Eine einfache Programmiersprache. Programmieren in Haskell 1

Algorithmen und Programmieren 1 Funktionale Programmierung - Musterlösung zu Übung 4 -

1 - FortProg ist: [ ] objekt-orientiert; [ ] funktional; [ ] logisch; [ ] manchmal nicht auszuhalten

Einfache Liste: Ein Stapel (Stack) Ansatz. Schaubild. Vorlesung 1. Handout S. 2. Die einfachste Form einer Liste ist ein Stapel (stack).

Transkript:

Programmieren in Haskell Abstrakte Datentypen

Einführung Man unterscheidet zwei Arten von Datentypen: konkrete Datentypen: beziehen sich auf eine konkrete Repräsentation in der Sprache. Beispiele: Listen, Bäume abstrakte Datentypen: nicht an eine konkrete Repräsentation gebunden. Werden definiert durch Operationen, die auf diesem Datentyp arbeiten. Werden durch eine Schnittstelle definiert. Die konkrete Repräsentation der Daten ist nicht sichtbar.

Abstrakte Datentypen werden durch eine Schnittstelle definiert die konkrete Implementierung des Datentyps ist für den Benutzer des Datentyps nicht sichbar die Implementierung des Datentyps kann verändert werden, ohne dass sich der Code der diesen Datentyp verwendet, ändern muss In Haskell werden abstrakte Datentypen durch Module unterstützt.

Module in Haskell Ein Haskell-Modul ist eine Datei, welche wie folgt eingeleitet wird: module <Name> (<Exportliste>) where Nur die Datentypen und Funktionen, die in <Exportliste> angegeben werden, sind nach aussen hin sichtbar Wenn <Exportliste> weggelassen wird, sind alle Definitionen nach aussen sichtbar.

Exportieren von Datentypen data List a = Nil Cons a (List a) module Liste (List) where Dies exportiert nur den Datentyp List, nicht aber die Konstruktoren Nil und Cons. Diese können in dem importierenden Modul nicht verwendet werden module Liste (List(Nil, Cons)) where exportiert auch die Konstruktoren alternativ: module Liste (List(..)) where exportiert alle Konstruktoren eines Datentyps

Beispiel: Stack Ein Stack ist ein Datentyp, der eine Menge von gleichartigen Elementen aufnehmen kann. Er unterstützt drei Operationen: push x s: Legt ein neues Element x auf den Stack s pop s: Entfernt das oberste Element vom Stack top s: Liefert das oberste Element des Stacks s, ohne dieses zu entfernen Last In First Out (LIFO)-Strategie: Das letzte Element, was auf den Stack gelegt wurde, ist das erste, was wieder heruntergenommen wird.

Stack-Schnittstelle in Haskell module Stack (Stack,push,pop,top,emptyStack,stackEmpty) where emptystack:: Stack a stackempty:: Stack a -> Bool push :: a-> Stack a -> Stack a pop :: Stack a -> Stack a top :: Stack a -> a emptystack liefert einen neuen, leeren Stack stackempty überprüft, ob der Stack leer ist push legt ein Element auf den Stack pop entfernt das oberste Element vom Stack top liefert das oberste Element vom Stack, ohne es zu entfernen

Implementierung (I) data Stack a = EmptyStk Stk a (Stack a) emptystack = EmptyStk stackempty EmptyStk = True stackempty _ = False push x s = Stk x s pop EmptyStk = error "pop from an empty stack" pop (Stk _ s) = s top EmptyStk = error "top from an empty stack" top (Stk x _) = x

Implementierung (II) newtype Stack a = Stk [a] emptystack = Stk [] stackempty (Stk []) = True stackempty (Stk _ ) = False push x (Stk xs) = Stk (x:xs) pop (Stk []) = error "pop from an empty stack" pop (Stk (_:xs)) = Stk xs top (Stk []) = error "top from an empty stack" top (Stk (x:_)) = x

Darstellung Problem: Da die Implementierungen jeweils nach aussen hin nicht sichtbar sind, kann der Stack auch nicht angezeigt werden. Lösung: Definition einer eigenen show-funktion Version 1: instance (Show a) => Show (Stack a) where show EmptyStk = "-" show (Stk x s) = show x ++ " " ++ show s Version II: instance (Show a) => Show (Stack a) where show (Stk []) = "-" show (Stk (x:xs)) = show x ++ " " ++ show (Stk xs)

Beispiel: Queue Eine Queue (Schlange) ist vergleichbar mit einem Stack, nur dass sie nach einer FIFO (First In First Out)-Strategie arbeitet Das erste Element, das einer Queue hinzugefügt wurde, ist auch das erste, das wieder entfernt wird Eine Queue stellt die Operationen enqueue, dequeue und front bereit

Queue-Schnittstelle in Haskell module Queue (Queue,emptyQueue,queueEmpty,enqueue,dequeue,front) where emptyqueue :: Queue a queueempty :: Queue a -> Bool enqueue :: a -> Queue a -> Queue a dequeue :: Queue a -> Queue a front :: Queue a -> a emptyqueue liefert eine neue Queue queueempty überprüft, ob eine Queue leer ist enqueue fügt einer Queue ein neues Element hinzu dequeue entfernt das erste Element aus der Queue front liefert das erste Element der Queue

Implementierung (I) newtype Queue a deriving Show = Q [a] emptyqueue = Q [] queueempty (Q []) = True queueempty (Q _ ) = False enqueue x (Q q) = Q (q ++ [x]) dequeue (Q (_:xs)) = Q xs dequeue (Q []) = error "dequeue: empty queue" front (Q (x:_)) = x front (Q []) = error "front: empty queue" Problem: enqueue benötigt O(n) Zeit!

Implementierung (II) newtype Queue a = Q ([a],[a]) queueempty (Q ([],[])) = True queueempty _ = False emptyqueue = Q ([],[]) enqueue x (Q ([],[])) = Q ([x],[]) enqueue y (Q (xs,ys)) = Q (xs,y:ys) dequeue (Q ([],[])) = error "dequeue:empty queue" dequeue (Q ([],ys)) = Q (tail(reverse ys), []) dequeue (Q (x:xs,ys)) = Q (xs,ys) front (Q ([],[])) front (Q ([],ys)) = error "front:empty queue" = last ys front (Q (x:xs,ys)) = x Alle Operationen laufen in O(1) Zeit, nur wenn die erste Liste leer ist, benötigen dequeue und front O(n) Zeit

Priority Queues Eine Priority Queue ist eine Queue, bei der jedes Element mit einer Priorität verknüpft ist Die dequeue-operation entfernt dann das Element mit der größten Priorität

Schnittstelle module PQueue (PQueue,emptyPQ,pqEmpty,enPQ,dePQ,frontPQ) wher emptypq :: (Ord a) => PQueue a pqempty :: (Ord a) => PQueue a -> Bool enpq :: (Ord a) => a -> PQueue a -> PQueue a depq :: (Ord a) => PQueue a -> PQueue a frontpq :: (Ord a) => PQueue a -> a emptypq liefert eine neue Queue pqempty überprüft, ob eine Queue leer ist enpq fügt einer Queue ein neues Element hinzu depq entfernt das erste Element aus der Queue frontpq liefert das erste Element der Queue

Implementierung newtype PQueue a deriving Show = PQ[a] emptypq = PQ [] pqempty (PQ []) = True pqempty _ = False enpq x (PQ q) = PQ (insert x q) where insert x [] = [x] insert x r@(e:r') x > e = x:r otherwise = e:insert x r' depq (PQ []) = error "depq:empty priority queue" depq (PQ (x:xs)) = PQ xs frontpq (PQ [])= error "frontpq:empty priority queue" frontpq (PQ(x:xs)) = x

Mengen Eine Menge ist eine ungeordnete Sammlung von unterschiedlichen Elementen Ein Element kann auf Mitgliedschaft in einer Menge hin überprüft werden, kann einer Menge hinzugefügt oder aus einer Menge entfernt werden

Mengen-Schnittstelle in Haskell module Set (Set,emptySet,setEmpty,inSet,addSet,delSet) where emptyset :: Set a setempty :: Set a -> Bool inset :: (Eq a) => a -> Set a -> Bool addset :: (Eq a) => a -> Set a -> Set a delset :: (Eq a) => a -> Set a -> Set a emptyset erzeugt eine neue Menge setempty überprüft, ob die Menge leer ist inset überprüft, ob ein Element in einer Menge enthalten ist addset fügt ein Element der Menge hinzu delset entfernt ein Element aus der Menge

Implementierung newtype Set a = St [a] emptyset = St [] setempty (St []) = True setempty _ = False inset x (St xs) = elem x xs addset x (St a) = St (x:a) delset x (St xs) = St (filter (/= x) xs)

Was haben wir heute gesehen? abstrakte Datentypen Stacks Queues Priority Queues Mengen

schöne Semesterferien!