Softwaretechnik. Funktionale Programmierung. Christian Lindig. 23. Januar 2006. Lehrstuhl für Softwaretechnik Universität des Saarlandes

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

Gliederung. n Teil I: Einleitung und Grundbegriffe. n Teil II: Imperative und objektorientierte Programmierung

Programmieren in Haskell Das Haskell Typsystem

III.1 Prinzipien der funktionalen Programmierung - 1 -

Grundlagen der Programmierung 3 A

Übergang von funktionaler zu OOP. Algorithmen und Datenstrukturen II 1

Funktionale Programmierung mit Haskell. Jan Hermanns

Grundlagen der Programmierung 3 A

Haskell for Hackers... or why functional programming matters

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

Einführung in Haskell

Grundlagen der Programmierung 2 (1.A)

Grundlegende Datentypen

Die Definition eines Typen kann rekursiv sein, d.h. Typ-Konstruktoren dürfen Elemente des zu definierenden Typ erhalten.

Funktionale Programmierung mit Haskell

Grundlagen der Programmierung 2 (1.A)

Einführung in die funktionale Programmierung

Grundlagen der Programmierung 2 (1.A)

WS 2011/2012. RobertGiegerich. November 12, 2013

Theorie zu Übung 8 Implementierung in Java

WS 2011/2012. RobertGiegerich. November 12, 2013

Übergang von funktionaler zu OOP. Algorithmen und Datenstrukturen II 1

Funktionale Programmierung mit modernem C++ Rainer Grimm Schulungen, Coaching und Technologieberatung

Haskell. Grundlagen der Programmierung 2. Grundlagen der Programmierung 2 (1.A) Bücher, Literatur, URLs. Haskell. Einführung

Grundlagen der Programmierung 2 (1.A)

Algorithmen und Datenstrukturen CS1017

Funktionale Programmierung mit C++

Die Schnittstelle Comparable

ALP I. Funktionale Programmierung

Haskell. Grundlagen der Programmierung 2. Grundlagen der Programmierung 2: Geplanter Inhalt der ersten Hälfte. Prof. Dr. Manfred Schmidt-Schauß

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

Polymorphismus 44. Function.hpp. #include <string>

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

Grundlagen der Programmierung 2

Grundlagen der Programmierung 2 (1.A)

Funktionale Programmierung

ALP I. Funktionale Programmierung

Algorithmen und Datenstrukturen II

Beispiel: Hamming-Folge Erzeuge eine Folge X = x 0,x 2,... mit folgenden Eigenschaften: 1. x i+1 > x i für alle i

Probeklausur: Programmierung WS04/05

Crashkurs: Haskell. Mentoring FU Berlin Felix Droop

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

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

12 Abstrakte Klassen, finale Klassen und Interfaces

WS 2012/2013. Robert Giegerich. 21. November 2012

Fahrplan. Inhalt. Ähnliche Funktionen der letzten Vorlesung. Muster der primitiven Rekursion. Ähnliche Funktionen der letzten Vorlesung

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

Programmieren in Java

Grundlegende Datentypen

Objektorientierte Programmierung mit C++ SS 2007

II.4.5 Generische Datentypen - 1 -

Typ-Polymorphismus. November 12, 2014

Grundlegende Datentypen

Programmieren in Haskell Einführung

Polymorphismus 179. Function.h. #include <string>

Praktische Informatik 3: Funktionale Programmierung Vorlesung 6 vom : Funktionen Höherer Ordnung II und Effizienzaspekte

Funktionale Programmierung

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

Software Entwicklung 1

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

Funktionale Programmierung mit C++

Funktioniert s? Funktionale Programmierung für Anfänger

WS 2013/2014. Robert Giegerich. 11. Dezember 2013

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

II.3.1 Rekursive Algorithmen - 1 -

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

Funktionale Programmierung mit modernem C++ Rainer Grimm Schulungen, Coaching und Technologieberatung

Funktionale Programmierung Grundlegende Datentypen

Die abstrakte Klasse Expression:

Grundzüge der Programmierung. Wiederverwendung POLYMORPHIE

Programmieren in Haskell

Funktionale Programmierung

Praktische Informatik 3: Funktionale Programmierung Vorlesung 13 vom : Scala Eine praktische Einführung

Programmierkurs II. Typsynonyme & algebraische Datentypen

Programmieren in Haskell

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

Programmieren in Haskell

14. Java Objektorientierung. Klassen, Vererbung, Kapselung

Probeklausur zur Vorlesung

Programmierkurs Java

Closures in Java. Michael Wiedeking. Java Forum Stuttgart Juli MATHEMA Software GmbH (

Kapitel 9. Programmierkurs. Attribute von Klassen, Methoden und Variablen. 9.1 Attribute von Klassen, Methoden und Variablen

WS 2013/2014. Robert Giegerich. 11. Dezember 2013

JAVA 06: Gemischte einfache Fragen zu Java

Programmieren in Haskell Einstieg in Haskell

Praktische Informatik 3: Funktionale Programmierung Vorlesung 13 vom : Scala Eine praktische Einführung

Programmieren in Haskell Programmiermethodik

Objektorientierte Programmierung Studiengang Medieninformatik

Polymorphie. 15. Java Objektorientierung II

14 Abstrakte Klassen, finale Klassen, Interfaces

Programmieren in Haskell Einführung

Aufgabe 1 Basiswissen zur Vorlesung (8 Punkte)

Programmieren in Java

Transkript:

Softwaretechnik Funktionale Programmierung Christian Lindig Lehrstuhl für Softwaretechnik Universität des Saarlandes 23. Januar 2006

Quicksort in Java static void sort(int a[], int lo0, int hi0) { int lo = lo0; int hi = hi0; if (lo >= hi) { return; } int mid = a[(lo + hi) / 2]; while (lo < hi) { while (lo<hi && a[lo] < mid) { lo++; } while (lo<hi && a[hi] >= mid) { hi--; } if (lo < hi) {int T=a[lo]; a[lo]=a[hi]; a[hi]=t;} } if (hi < lo) { int T=hi; hi=lo; lo=t;} sort(a, lo0, lo); sort(a, lo == lo0? lo+1 : lo, hi0); }

Quicksort in Haskell qsort [] = [] qsort (x:xs) = qsort [y y <- xs, y <= x] ++ [x] ++ qsort [y y <- xs, y > x]

Quicksort in Haskell qsort [] = [] qsort (x:xs) = qsort [y y <- xs, y <= x] ++ [x] ++ qsort [y y <- xs, y > x] Definition von qsort ist deklarativ. Pattern-Matching vereinfacht die Fallunterscheidung. qsort ist polymorph: qsort [3,6,7,3,9,6,1] = [1,3,3,6,6,7,9] qsort [( h,5),( b,2),( b,1)]= [( b,1),( b,2),( h,5)] qsort besitzt einen Typ: qsort :: Ord a => [a] -> [a] Auf den zu sortierenden Elementen muss eine Ordnung definiert sein.

Anwendungen funktionaler Konzepte Spreadsheets: der Wert einer Zelle ist (1) eine Konstante oder (2) eine Funktion über den Wert anderer Zellen. C++ Templates bilden eine funktionale Programmiersprache. XSLT ist eine funktionale Sprache zur Transformation von XML-Dokumenten. XQuery ist eine Anfrage-Sprache (ähnlich SQL) zur Extraktion von Daten aus XML-Dokumenten.

In FP implementierte Anwendungen MLdonkey edonkey File-Sharing Unison zur Synchronization von Dateien zwischen Laptop und Desktop Ericsson Telefonanlagen DARCS dezentrale Versionskontrollsystem Compiler: SML/NJ, GHC, OCaml, Skala, XDuce, Galax,...

Haskell Syntax www.haskell.org (1, 3.1415, c ) Tripel mit Literalen [1, 4, 6] Liste mit Literalen 1:4:6:[] Liste mit (:) Operator length [1,2,3] Funktionsaufruf max 2 x zwei Argumente max 2 (x*x) zwei Argumente 2 == x Gleichheits-Operator == 2 max x max als Infix-Operator (==) 2 x == als (Prefix-)Funktion double x = 2*x Funktionsdefinition [ x x <- [1..], even x] list comprehension

Rekursion Das Fehlen von Variablen erzwingt es, Iteration durch Rekursion auszudrücken. length :: [a] -> Int length [] = 0 length (x:xs) = 1 + len xs take :: Int -> [a] -> [a] take _ [] = [] take 0 xs = [] take n (x:xs) = x : take (n-1) xs Fortgeschrittene Programmiertechniken verlagern Rekursion in spezielle Kombinatoren (foldl), so dass Rekursion nicht explizit ist: length = foldl (\n _ -> n + 1) 0

Funktionen sind Werte Funktionen als Parameter In Haskell (oder ML, Scheme,... ) ist eine Funktion ein Wert, der genauso wie ein Integer oder String übergeben werden kann. Hier ist p ein Prädikat: filter :: (a -> Bool) -> [a] -> [a] filter p [] = [] filter p (x:xs) = if p x then x : filter p xs else filter p xs filter even [1..10] = [2,4,6,8,10] Genauso, wie man ein Integer 4 verwenden kann, ohne ihn zu benennen, kann man eine anonyme Funktion verwenden: filter (\x -> x mod 2 == 0) [1..10] = [2,4,6,8,10]

Funktionen sind Werte Funktionen als Ergebnis Wird eine Funktion unterversorgt, entsteht eine Funktion als Ergebnis: filter_even = filter even Der Typ der neuen Funktion kann leicht aus der unterversorgten Funktion abgeleitet werden: filter :: (a -> Bool) -> [a] -> [a] even :: Int -> Bool filter_even :: [Int] -> [Int] Unterversorgung kann als Spezialisierung allgemeiner (also wiederverwendbarer) Funktionen aufgefasst werden.

Typinferenz Moderne funktionale Programmiersprachen besitzen ein statisches Typsystem. Jeder Name und jeder Teil-Ausdruck besitzt einen Typ, der zur Übersetzungszeit bestimmt werden kann. Mit Ausnahme von Datentypen müssen Typen nicht deklariert werden. Ausschnitt aus einer interaktiven Sitzung mit Hugs, einem Haskell-Interpreter: Main> :t filter even filter even :: Integral a => [a] -> [a] Main> :t (\f g x -> f (g x)) \f g x -> f (g x) :: (a -> b) -> (c -> a) -> c -> b

Datentypen Summen- und Produkttypen Produkttyp Record, Tupel enthält alle Daten gleichzeitig Summentyp varianter Record enthält eine Alternative data Time data Shape = Time (Int, Int) = Circle Triangle Square Pentagon Datentypen können parametrisiert werden: data Result a = Ok a Wrong apply f (Ok a) = Ok (f a) apply f Wrong = Wrong

Datentypen und Pattern-Matching Primitive und neu definierte Datentypen können mit Pattern-Matching zerlegt werden: data Tree a = Empty Node (Tree a) a (Tree a) height :: Tree a -> Int height Empty = 0 height (Node left _ right) = 1 + max (height left) (height right) Rekursive Funktionen sind die Entsprechung zu rekursiven Datentypen.

Persistenz Da es keine Seiteneffekte gibt, berechnen eine Funktion (konzeptionell) immer eine neue Datenstruktur. insert x Empty = Node Empty x Empty insert x (Node left y right) x == y = Node left y right x < y = Node (insert x left) y right otherwise = Node left y (insert x right) x = Empty y = insert "hallo" x Das Einfügen von "hallo" in x verändert x nicht: height x = 0

Polymorphismus Funktionen und Datenstrukturen in FP sind oft polymorph: sie funktionieren uniform für alle Datentypen. length [1,2] = 2 length [(1,2),(2,3),(4,5)] = 3 Der Polymorphismus einer Funktion oder eines Datentyps spiegelt sich in seinem Typ wieder, der Typvariablen enthält: length :: [a] -> Int data Tree a = Empty Node (Tree a) a (Tree a) Der Polymorphismmus in FP wird deswegen parametrischer Polymorphismus genannt.

Implementierung von Polymorphismus Daten werden in FP intern uniform repräsentiert deswegen existiert eine polymorphe Funktion im Maschinencode nur einmal. Eine polymorphe Funktion ignoriert bestimmte Teile einer Datenstruktur diese Teile werden durch Typvariablen beschrieben. Beispiel: length ignoriert den Inhalt einer Liste. 23-4 28

Grenzen von Polymorphismus qsort [] = [] qsort (x:xs) = qsort [y y <- xs, y <= x] ++ [x] ++ qsort [y y <- xs, y > x] (++) ist polymorph: [a] -> [a] -> [a] <= und > können nicht polymorph sein: sie hängen vom Typ der zu sortierenden Liste ab es kann keine einheitliche Implementierung für (<=) existieren. Wir benötigen eine typ-spezifische Implementierung für (<=). Dies wäre kein Problem in Java, aber in Haskell oder ML?

Polymorphismus Typ-Klassen und Ad-Hoc Polymorphismus Haskell erlaubt es, eine typ-spezifische Implementierung für Funktionen wie (==) oder (<=) anzugeben. Der Typ von qsort zeigt an, dass wir nur solche Liste sortiert werden können, für die eine Ordnung definiert ist: qsort :: Ord a => [a] -> [a] Die Ordung (<=) ist typ-spezifisch definiert; ähnlich wie in OOP wird die richtige Implementierung zur Laufzeit ausgewählt. Diese Form von Polymorphismus heißt Ad-Hoc Polymorphismus oder Überladung.

Vergleich: Polymorphismus in OO Eine Variable vom Typ A kann auch jeden Wert vom Typ B A aufnehmen. Dabei werden allerdings alle über A hinausgehenden Eigenschaften vergessen : Integer i = new Integer(123); // i.intvalue() == 123 Object o = new Integer(123); System.out.println(o.intValue); // intvalue unbekannt Subtyping-Polymorphismus erlaubt inhomogene Container (Listen, Maps, etc.), erfordert allerdings Typ-Konvertierungen zur Laufzeit. Vector v = new Vector(); v.addelement(new Integer(1)); // addelement(object o) v.addelement(new String("two")); Integer x = (Integer) v.get(0); // Object get(int) String y = (String) v.get(1);

Dynamische Bindung in Java public class EvenOdd { public EvenOdd () {} public boolean even(int n) { if (n == 0) { return true ;} else if (n == 1) { return false ;} else { return this.odd(n-1); } } public boolean odd(int n) { if (n == 0) { return false ;} else if (n == 1) { return true ;} else { return this.even(n-1); } } } public class FastEvenOdd extends EvenOdd { public FastEvenOdd() {} public boolean even(int n) { return (n%2 == 0); } } // FastEvenOdd x = new FastEvenOdd(); x.even(1000)

Statische Binding in FP even 0 = True even 1 = False even n = odd (n-1) odd 0 odd 1 odd n = False = True = even (n-1) Die Definitionen von even und odd können nachträglich nicht mehr ergänzt werden. Eine dynamischer Bindung vergleichbare Ausdruckskraft entsteht durch Funktionen höherer Ordnung. Diese müssen aber geplant werden. map f [] = [] map f (x:xs) = f x : map f xs

Evolution von Software Klassen, Module und Polymorphismus sind nicht unbedingt erforderlich für Software, die einmalig entwickelt und dann eingesetzt wird. Diese Konzepte aber sind wichtig für Software, die erweiterbar bleiben soll; als wiederverwendbare Basis als Teil größerer Projekte dienen soll. Programmiersprachen wie Java, C++, ML und Haskell unterstützen diese Konzepte syntaktisch, während sie in Programmiersprachen wie C oder Pascal nur durch Konventionen simuliert werden können.

Sind OO-Systeme einfacher erweiterbar? Betrachte Datenstruktur mit Operationen; : einfach, : aufwändig hin- Alternative zufügen Operation zufügen OO Eine Klasse pro Alternative, eine Methode pro Operation Eine Klasse hinzufügen hin- FP Eine Funktion pro Operation, ein Summand per Alternative In allen Funktionen: Pattern- Matching ergänzen Eine Funktion hinzufügen Eine Methode in allen Klassen hinzufügen

OO oder FP? Wenn Datenstrukturen häufiger ergänzt werden als Operationen, ist eine OO Modellierung einfacher: Daten GUI-Widgets (Button, Menu, Radio,... ) Operationen fest definierter Satz von Methoden wie draw(), select(). Andernfalls ist eine funktionale Modellierung einfacher: Daten abstrakter Syntax-Baum Operationen eval(), type check(), transform(),...

OO oder FP? Einfacher in FP und mit Modulen: Handhabung von Baumstrukturen (Pattern-Matching) Parametrisierung-im-Großen (ML Funktoren, Typklassen) Sicherheit durch Typsystem Einfacher mit OO: Kapselung von Zustand (in Objekten) Inkrementelle Programmentwicklung (Vererbung) Flexibilität auf Kosten von Sicherheit Diverse Programmiertechniken helfen, den Schwächen eines gewählten Paradigmas zu begegnen: Design-Patterns, Continuations, Monaden.

Ausblick In modernen Sprachen verschwimmen die Grenzen von FP und OO. OO-Sprachen übernehmen FP-Konzepte: Pyhton und Lua kennen anonyme Funktionen, Java hat innere Klassen, Generics führen parametrischen Polymorphismus ein. Objective Caml hat Klassen und Objekte. In Scala ist jede Funktion zugleich ein Objekt. Themen in der Forschung: generalisierte Summentypen, Nebenläufigkeit, Verteilung, vertrauenswürdiger Binärcode, Integration von XML als Datentyp, staged programming.