Programmieren in Haskell Programmiermethodik

Ähnliche Dokumente
Programmieren in Haskell

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

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

Programmieren in Haskell. Abstrakte Datentypen

Kapitel 3: Eine einfache Programmiersprache. Programmieren in Haskell 1

Programmieren in Haskell

Programmieren in Haskell Einstieg in Haskell

Programmieren in Haskell

Programmieren in Haskell

Funktionale Programmierung mit Haskell

Programmieren in Haskell

Programmieren in Haskell

Programmierkurs II. Typsynonyme & algebraische Datentypen

Was bisher geschah. deklarative Programmierung. funktionale Programmierung (Haskell):

Programmieren in Haskell

Programmieren in Haskell

Typklassen. Natascha Widder

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

Formale Methoden in der Informatik Wiederholung klassische Logik Konkrete Datentypen (algebraische Strukturen) Abstrakte Datentypen

Informatik-Seminar Thema 6: Bäume

Agenda. 1 Einleitung. 2 Binäre Bäume. 3 Binäre Suchbäume. 4 Rose Trees. 5 Zusammenfassung & Ausblick. Haskell Bäume. Einleitung.

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

2.3 Spezifikation von Abstrakten Datentypen

4.1 Bäume, Datenstrukturen und Algorithmen. Zunächst führen wir Graphen ein. Die einfachste Vorstellung ist, dass ein Graph gegeben ist als

Praktische Informatik 3: Funktionale Programmierung Vorlesung 4 vom : Typvariablen und Polymorphie

Was bisher geschah Funktionale Programmierung in Haskell: Algebraische Datentypen Pattern Matching Polymorphie Typklassen Rekursive Datentypen:

9 Algebraische Datentypen

Grundlagen der Programmierung 3 A

ALP I Induktion und Rekursion

Workshop Einführung in die Sprache Haskell

Musterlösung zur 2. Aufgabe der 4. Übung

INFORMATIK FÜR BIOLOGEN

Haskell, Typen, und Typberechnung. Grundlagen der Programmierung 3 A. Einige andere Programmiersprachen. Typisierung in Haskell

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

[10] Software Transactional Memory in Haskell, Tortenwurf und Aufgabenblatt 7

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

Gliederung. Algorithmen und Datenstrukturen I. Listen in Haskell: Listen in Haskell: Listen in Haskell. Datentyp Liste Strings Listenkomprehension

ALP I. Funktionale Programmierung

Tutoraufgabe 1 (Auswertungsstrategie):

Haskell, Typen, und Typberechnung. Grundlagen der Programmierung 3 A. Überladung und Konversion in Haskell. Typisierung in Haskell

Funktionale Programmierung mit Haskell

Funktionen höherer Ordnung

Funktionale Programmierung ALP I. Die Natur rekursiver Funktionen SS Prof. Dr. Margarita Esponda. Prof. Dr.

Strukturelle Rekursion und Induktion

Verträge für die funktionale Programmierung Design und Implementierung

Einführung in die Informatik 2

Programmieren in Haskell Felder (Arrays)

WS 2011/2012. Georg Sauthoff 1. October 18, 2011

Wiederholung ADT Menge Ziel: Verwaltung (Finden, Einfügen, Entfernen) einer Menge von Elementen

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

Funktionale Programmierung Grundlegende Datentypen

Praktische Informatik 3: Funktionale Programmierung Vorlesung 3 vom : Algebraische Datentypen

Crashkurs Haskell Mentoring WiSe 2016/17. Anja Wolffgramm Freie Universität Berlin

Haskell in der Schule - (K)ein Thema? Ralf Dorn - Dennis Buchmann - Felix Last - Carl Ambroselli

Praktische Informatik 3: Funktionale Programmierung Vorlesung 5 vom : Funktionen Höherer Ordnung I

Unendliche Listen und Bäume

Einführung in die Funktionale Programmierung mit Haskell

Einführung in die Funktionale Programmierung mit Haskell

Kapitel 12: Induktive

Abstrakte Datentypen I

Tutoraufgabe 1 (Datenstrukturen in Haskell):

Basiskonstrukte von Haskell

1 Der Baum. Informatik I: Einführung in die Programmierung 11. Bäume. Bäume in der Informatik. Bäume in der Informatik - Definition.

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

Funktionale Programmierung ALP I. λ Kalkül. Teil 2 WS 2012/2013. Prof. Dr. Margarita Esponda. Prof. Dr. Margarita Esponda

Funktionale Programmierung. Das Funktionale Quiz. Das Funktionale Quiz. Das Funktionale Quiz

Bemerkung: Heapsort. Begriffsklärung: (zu Bäumen) Begriffsklärung: (zu Bäumen) (2) Heapsort verfeinert die Idee des Sortierens durch Auswahl:

Allgemeine Hinweise: TECHNISCHE UNIVERSITÄT MÜNCHEN. Name Vorname Studiengang Matrikelnummer. Hörsaal Reihe Sitzplatz Unterschrift

Definieren Sie eine Funktion circlearea zur Berechnung der Fläche eines Kreises mit gegebenen Radius (Float).

Grundlagen der Programmierung 2. Bäume

Tag 7. Pattern Matching und eigene Datentypen

Praktische Informatik 3: Einführung in die Funktionale Programmierung Vorlesung vom : Rekursive Datentypen

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

Programmieren in Haskell Einführung

Teil 4: Rekursion und Listen

2.5 Listen. Kurzschreibweise: [42; 0; 16] Listen werden mithilfe von [] und :: konstruiert.

Computeranwendung und Programmierung (CuP)

Organisatorisches. drei Gruppen Gruppe 1: 10:10-11:40, Gruppe 2: 11:45-13:15 Gruppe 3: 13:20-14:50

Organisatorisches. Neue Übungsblätter: Nur mehr elektronisch? Abgabe Di, , 14 Uhr bis Do, , 8Uhr

1 Der Baum. Informatik I: Einführung in die Programmierung 11. Bäume. Bäume in der Informatik. Bäume in der Informatik - Definition.

Zahlen in Haskell Kapitel 3

Lösung: InfA - Übungsblatt 07

Mathematik für Informatiker I

Transkript:

Programmieren in Haskell Programmiermethodik Peter Steffen Universität Bielefeld Technische Fakultät 12.01.2011 1 Programmieren in Haskell

Bisherige Themen Was soll wiederholt werden? Bedienung von hugs oder ghc Grundlegende Haskell-Funktionen Syntax und Semantik von Haskell Datentypen Typklassen Musik Lokale Definitionen mit where und let Programmieren mit Listen foldr und Kolleginnen Arrays Hash-Tabellen Ein- und Ausgabe Abstrakte Datentypen 2 Programmieren in Haskell

Spezifikation Aus dem Schülerduden Informatik: Präzise Darstellung und Beschreibung der Eigenschaften, der Verhaltensweisen, des Zusammenwirkens und des Aufbaus von Modellen, Programmen oder Systemen, wobei meist von Details abstrahiert wird und konkrete Implementierungen keine Rolle spielen. Die Spezifikation stellt im Idealfall eine vollständig formale, von Implementierungen unabhängige Beschreibung des Verhaltens eines zu erstellenden Systems dar. Das Ziel einer Spezifikation liegt erstens in einem klaren Verständnis des Problems, seiner besonderen Eigenschaften und seiner Lösungen. Zweitens dient sie als Vergleichsmaß dafür, ob ein System oder Programm den gewünschten Anforderungen genügt. 3 Programmieren in Haskell

Spezifikation des Sortierproblems Informell: Gesucht ist eine Funktion sort, die eine gegebene Liste von Elementen aufsteigend anordnet. Beispiele: sort [8, 3, 5, 3, 6, 1] [1, 3, 3, 5, 6, 8] sort "hello world" " dehllloorw" sort ["Bein", "Anfall", "Anna"] ["Anfall", "Anna", "Bein"] sort [(1, 7), (1, 3), (2, 2)] [(1, 3), (1, 7), (2, 2)] 4 Programmieren in Haskell

Spezifikation der Sortierfunktion sort :: (Ord a) => [a] -> OrdList a ordered :: (Ord a) => [a] -> Bool ordered [] = True ordered [a] = True ordered (a1:a2:as) = a1 <= a2 && ordered (a2:as) Spezifikation 1: Für alle Listen x :: [τ] muß gelten: ordered (sort x) = True. (1) Reicht das? Nein: sort xs = [] erfüllt ebenfalls die Spezifikation 5 Programmieren in Haskell

Spezifikation der Sortierfunktion sort :: (Ord a) => [a] -> OrdList a ordered :: (Ord a) => [a] -> Bool ordered [] = True ordered [a] = True ordered (a1:a2:as) = a1 <= a2 && ordered (a2:as) Spezifikation 1: Für alle Listen x :: [τ] muß gelten: ordered (sort x) = True. (1) Reicht das? Nein: sort xs = [] erfüllt ebenfalls die Spezifikation 5 Programmieren in Haskell

Spezifikation der Sortierfunktion sort :: (Ord a) => [a] -> OrdList a ordered :: (Ord a) => [a] -> Bool ordered [] = True ordered [a] = True ordered (a1:a2:as) = a1 <= a2 && ordered (a2:as) Spezifikation 1: Für alle Listen x :: [τ] muß gelten: ordered (sort x) = True. (1) Reicht das? Nein: sort xs = [] erfüllt ebenfalls die Spezifikation 5 Programmieren in Haskell

Spezifikation der Sortierfunktion sort :: (Ord a) => [a] -> OrdList a ordered :: (Ord a) => [a] -> Bool ordered [] = True ordered [a] = True ordered (a1:a2:as) = a1 <= a2 && ordered (a2:as) Spezifikation 1: Für alle Listen x :: [τ] muß gelten: ordered (sort x) = True. (1) Reicht das? Nein: sort xs = [] erfüllt ebenfalls die Spezifikation 5 Programmieren in Haskell

Multimengen die leere Multimenge, a die einelementige Multimenge, die genau ein Vorkommen von a enthält, x y die Vereinigung der Elemente von x und y; das + im Vereinigungszeichen deutet an, dass sich die Vorkommen in x und y akkumulieren. x = x (2) x = x (3) x y = y x (4) (x y) z = x (y z) (5) 6 Programmieren in Haskell

Multimengen bag :: [a] -> Bag a bag [] = bag (a:as) = a bag as Eine Liste x enthält alle Elemente von y, falls bag x = bag y. In diesem Fall heißt x Permutation von y. Spezifikation 2: Für alle Listen x :: [τ] muß gelten: ordered (sort x) = True bag (sort x) = bag x. (6) Dadurch ist sort als mathematische Funktion, nicht aber als Programm, eindeutig bestimmt. 7 Programmieren in Haskell

Abstrakter Datentyp Multimenge module Bag (Bag, emptybag, bagempty, inbag, addbag, delbag, appendbag, headbag, tailbag) where import List emptybag :: Bag a bagempty :: Bag a -> Bool inbag :: (Eq a) => a -> Bag a -> Bool addbag :: (Eq a) => a -> Bag a -> Bag a delbag :: (Eq a) => a -> Bag a -> Bag a appendbag :: Bag a -> Bag a -> Bag a headbag :: Bag a -> a tailbag :: Bag a -> Bag a 8 Programmieren in Haskell

Abstrakter Datentyp Multimenge emptybag erzeugt eine neue Multimenge bagempty überprüft, ob eine Multimenge leer ist inbag überprüft, ob ein Element in der Multimenge enthalten ist addbag fügt ein Element einer Multimenge hinzu delbag löscht ein Element aus einer Multimenge appendbag vereinigt zwei Multimengen headbag gibt das erste Element aus der Multimenge aus tailbag entfernt das erste Element aus der Multimenge 9 Programmieren in Haskell

Implementierung newtype Bag a = Bag [a] emptybag = Bag [] bagempty (Bag []) = True bagempty _ = False inbag x (Bag xs) = elem x xs addbag x (Bag xs) = Bag (x:xs) delbag x (Bag xs) = Bag (filter (/= x) xs) appendbag (Bag xs) (Bag ys) = Bag (xs ++ ys) headbag (Bag []) = error "headbag on empty bag" headbag (Bag (x:xs)) = x tailbag (Bag []) = error "tailbag on empty bag" tailbag (Bag (x:xs)) = Bag xs instance (Eq a, Ord a) => Eq (Bag a) where (Bag xs) == (Bag ys) = sort xs == sort ys 10 Programmieren in Haskell

Strukturelle Rekursion auf Listen length :: [a] -> Int length [] = 0 length (a:as) = 1 + length as -- vordefiniert Die Funktion length folgt dem Schema der strukurellen Rekursion. Für jeden Konstruktor des Datentyps, [] und (:), gibt es eine Gleichung. Der Konstruktor (:) ist rekursiv im zweiten Argument, über dieses Argument erfolgt der rekursive Aufruf. Man sagt, die Funktion ist strukturell rekursiv definiert. 11 Programmieren in Haskell

Strukturelle Rekursion auf Listen Rekursionsbasis: [] Rekursionsschritt: (a:as) Schema der strukturellen Rekursion auf Listen: f :: [σ] -> τ f [] = e 1 f (a : as) = e 2 where s = f as Dabei sind e 1 und e 2 Ausdrücke vom Typ τ und e 2 darf die Variablen a, as und s (nicht aber f ) enthalten. Mit s wird gerade die Lösung für as bezeichnet. Tritt s nur einmal in e 2 auf, kann man natürlich für s auch direkt f as einsetzen. 12 Programmieren in Haskell

Sortieren durch Einfügen insertionsort :: (Ord a) => [a] -> OrdList a insertionsort [] = e 1 insertionsort (a : as) = e 2 where s = insertionsort as insertionsort :: (Ord a) => [a] -> OrdList a insertionsort [] = [] insertionsort (a:as) = insert a s where s = insertionsort as 13 Programmieren in Haskell

Sortieren durch Einfügen insertionsort :: (Ord a) => [a] -> OrdList a insertionsort [] = e 1 insertionsort (a : as) = e 2 where s = insertionsort as insertionsort :: (Ord a) => [a] -> OrdList a insertionsort [] = [] insertionsort (a:as) = insert a s where s = insertionsort as 13 Programmieren in Haskell

Erweitertes Rekursionsschema Erweitertes Rekursionsschema: g :: σ 1 -> [σ 2 ] -> τ g i [] = e 1 g i (a : as) = e 2 where s = g e 3 as wobei e 1 die Variable i, e 2 die Variablen i, a, as und s und e 3 die Variablen i, a und as enthalten darf. insert :: (Ord a) => a -> OrdList a -> OrdList a insert a [] = e 1 insert a (a : as) = e 2 where s = insert e 3 as 14 Programmieren in Haskell

Insert insert a [] = [a] insert a (a : as) a <= a = e 21 otherwise = e 22 where s = insert e 3 as insert :: (Ord a) => a -> [a] -> [a] insert a [] = [a] insert a (a :as) a <= a = a:a :as otherwise = a :insert a as 15 Programmieren in Haskell

Strukturelle Rekursion auf Bäumen data Tree a = Nil Leaf a Br (Tree a) (Tree a) deriving Show Rekursionsbasis (Nil) Das Problem wird für den leeren Baum gelöst. Rekursionsbasis (Leaf a) Das Problem wird für das Blatt Leaf a gelöst. Rekursionsschritt (Br l r) Um das Problem für den Baum Br l r zu lösen, werden rekursiv Lösungen für l und r bestimmt, die zu einer Lösung für Br l r erweitert werden. 16 Programmieren in Haskell

Strukturelle Rekursion auf Bäumen Schema der strukturellen Rekursion auf Bäumen: f :: Tree σ -> τ f Nil = e 1 f (Leaf a) = e 2 f (Br l r) = e 3 where sl = f l sr = f r e 3 darf dabei l, r, sl und sr enthalten, nicht aber f. 17 Programmieren in Haskell

Funktionen auf Bäumen size berechnet die Anzahl der Blätter eines Baumes: size :: Tree a -> Integer size Nil = 1 size (Leaf _) = 1 size (Br l r) = size l + size r depth berechnet die Tiefe des Baumes, d.h. die Länge des längsten Pfades von der Wurzel bis zu einem Blatt: depth :: Tree a -> Integer depth Nil = 0 depth (Leaf _) = 0 depth (Br l r) = max (depth l) (depth r) + 1 18 Programmieren in Haskell

Das allgemeine Rekursionsschema data T a 1... a m = C 1 t 11... t 1n1... C r t r1... t rnr Wir unterscheiden zwei Arten von Argumenten: rekursive (d.h. t ij ist gleich T a 1... a m ) und nicht-rekursive. Seien l i1,..., l ipi mit 1 l i1 < l i2 < < l ipi n i die Positionen, an denen der Konstruktor C i rekursiv ist 19 Programmieren in Haskell

Strukturelle Rekursion Allgemeines Schema der strukturellen Rekursion: f :: T σ 1... σ m -> τ f (C 1 x 11... x 1n1 ) = e 1 where s 11 = f x 1l11... s 1p1 =... f x 1l1p1 f (C r x r1... x rnr ) = e r where s r1 = f x rlr1... s rpr = f x rlrpr Der Ausdruck e i darf die Variablen x i1,..., x ini und die Variablen s i1,..., s ipi enthalten. Ist p i = 0, so spricht man von einer Rekursionsbasis, sonst von einem Rekursionsschritt. 20 Programmieren in Haskell

Verstärkung der Rekursion Wir wollen eine Funktion entwickeln, die eine Liste von Elementen umkehrt. Wenn wir das Schema der strukturellen Rekursion anwenden, ergibt sich folgende Implementierung: reverse :: [a] -> [a] -- vordefiniert reverse [] = [] reverse (a:as) = reverse as ++ [a] Problem: In jedem Rekursionsschritt wird von der Funktion ++ die komplette bereits umgedrehte Liste durchlaufen. Die Laufzeit von reverse ist somit in O(n 2 ). 21 Programmieren in Haskell

Verstärkung der Rekursion Wir wollen eine bessere Implementierung von reverse systematisch herleiten. Idee: Wir programmieren eine Funktion, die ein schwierigeres Problem löst als verlangt, aber die es uns erlaubt, den Rekursionsschritt besser zu bewältigen. Diese Technik nennt man Verstärkung der Rekursion oder Programmieren durch Einbettung. Für reverse bedeutet dies: Im Rekursionsschritt müssen wir die Restliste umdrehen und an das Ergebnis eine Liste anhängen. Idee: Wir entwickeln eine Funktion, die beide Aufgaben gleichzeitig löst: Spezifikation: reel :: [a] -> [a] -> [a] reel x y = reverse x ++ y Aus dieser Spezifikation können wir die Definition von reel systematisch ableiten. 22 Programmieren in Haskell

Verstärkung der Rekursion Rekursionsbasis (x = []): reel [] y = reverse [] ++ y (Spezifikation) = [] ++ y (Def. reverse) = y (Def. (++)) 23 Programmieren in Haskell

Verstärkung der Rekursion Rekursionsschritt (x = a:as): reel (a:as) y = reverse (a:as) ++ y (Spezifikation) = (reverse as ++ [a]) ++ y (Def. reverse) = reverse as ++ ([a] ++ y) (Ass. (++)) = reverse as ++ (a:y) (Def. (++)) = reel as (a:y) (Spezifikation) 24 Programmieren in Haskell

Verstärkung der Rekursion reel :: [a] -> [a] -> [a] reel [] y = y reel (a:as) y = reel as (a:y) reverse xs = reverse xs ++ [] (Def. (++)) = (reel xs []) (Spezifikation) reverse :: [a] -> [a] reverse as = reel as [] 25 Programmieren in Haskell

Verstärkung der Rekursion reel :: [a] -> [a] -> [a] reel [] y = y reel (a:as) y = reel as (a:y) reverse xs = reverse xs ++ [] (Def. (++)) = (reel xs []) (Spezifikation) reverse :: [a] -> [a] reverse as = reel as [] 25 Programmieren in Haskell

Verstärkung der Rekursion reel :: [a] -> [a] -> [a] reel [] y = y reel (a:as) y = reel as (a:y) reverse xs = reverse xs ++ [] (Def. (++)) = (reel xs []) (Spezifikation) reverse :: [a] -> [a] reverse as = reel as [] 25 Programmieren in Haskell