Deklarative Programmierung Sibylle Schwarz Westsächsische Hochschule Zwickau Dr. Friedrichs-Ring 2a, RII 263 http://wwwstud.fh-zwickau.de/~sibsc/ [email protected] WS 2010/2011 1 Motivation . . . there are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies and the other way is to make it so complicated that there are no obvious deficiencies. The first method is far more difficult. Tony Hoare, 1980 ACM Turing Award Lecture 2 Programmierparadigmen Abstraktionsstufen: I Programmierung = Maschinencode I menschenlesbare symbolische Darstellung (Assembler) I Programmablauf- und Datenstrukturen (Algorithmen) (imperative und objektorientierte Sprachen) I deklarative Programmiersprachen (Constraint-Programmierung, logische Programmierung, funktionale Programmierung) Unterschied besteht darin, wie detailliert das Programm den Lösungsweg beschreiben muss. 3 Deklarative vs. imperative Programmierung deklarativ (beschreibend) Programm: Repräsentation eines Problems Programmelemente: Ausdrücke (Terme) und Gleichungen Programmierung: Modellierung der Aufgabe Ausführung: Lösung des beschriebenen Problems durch Umformung von Ausdrücken imperativ zustandsorientiert (von-Neumann-Typ) Programm: Repräsentation eines Algorithmus Programmelemente: Ausdrücke und Anweisungen Programmierung: Modellierung eines Verfahrens zur Lösung einer Aufgabe Ausführung des Lösungsverfahrens durch schrittweise Zustandsänderungen (Speicherbelegung) 4 Deklarative Programmierung Grundidee: Jedes Programm ist ein mathematisches Objekt mit einer bekannten wohldefinierten Semantik funktionale Programmierung (z.B. Haskell, ML, Lisp): Programm: Menge von Funktions-Definitionen (Gleichungen zwischen Termen) Ausführung: Reduktion (Termersetzung) logische Programmierung (Prolog): Programm: Menge logischer Formeln (Horn-Klauseln) Ausführung: SLD-Resolution funktional-logische Programmierung (z.B. Mercury, Curry): Kombination funktionaler und logischer Konzepte Constraint-Programmierung: Programm: Menge von Constraints (z.B. Gleichungen, Ungleichungen, logische Formeln) Ausführung: Constraint-Löser (abhängig vom Constraint-Bereich) Beispiel: Constraints: Constraint-Löser: Menge linearer Gleichungen Gauß-Algorithmus 5 Einordnung in die Informatik Informatik Lehre von Darstellung und Verarbeitung von Information Anteil der Teilgebiete der Informatik: theoretische Informatik: Grundlagen formale Sprachen, Prädikatenlogik, Berechnungsmodell λ-Kalkül technische Informatik: praktische Informatik: Grundlagen und Anwendung Programmierung, Softwareentwicklung, Übersetzerbau, rapid Prototyping, ausführbare Spezifiktion, Verifikation deklarative Konzepte in Mainstream-Sprachen angewandte Informatik: Anwendung z.B. Finanzkalkulationen, sicherheitskritische Anwendungen, KI, Audio-Programmierung 6 Organisation der Lehrveranstaltung 8 Termine zu je I Vorlesung I Beispiele und schriftliche Übungen I Praktikum mit verschiedenen Zeitanteilen Prüfungsvorleistung: I Testat (regelmäßiges Lösen der schriftlichen und praktischen Aufgaben in den Übungen) alternative Prüfungsleistung: I Programmierprojekt: neue Autotoolaufgabe I Gruppen zu je drei Studenten I Präsentation / Vortrag am 25.1.2011 I elektronische Einschreibung bis 29.10.2010 I Aufgabenbeispiele: I Informationssicherheit: ElGamal, Diffie-Hellman I A+D: Rot-Schwarz-Bäume, Heaps 7 Literatur online: http://www.haskell.org/ Informationen, Download, Dokumentation, Tutorials, . . . Bücher: I Graham Hutton: Programming in Haskell, Cambridge 2007 I Klassiker (englisch): http://haskell.org/haskellwiki/Books deutsch: I I I Peter Pepper und Petra Hofstedt: Funktionale Programmierung. Sprachdesign und Programmiertechnik Springer 2006 Manuel Chakravarty und Gabriele Keller: Einführung in die Programmierung mit Haskell Pearson 2004 Lehrunterlagen von Prof. Schmidt (FH Wedel) http: //www.fh-wedel.de/~si/vorlesungen/fp/fp.html 8 Werkzeug und Stil Die Grenzen meiner Sprache bedeuten die Grenzen meiner Welt. Ludwig Wittgenstein speziell in der Informatik: We are all shaped by the tools we use, in particular: the formalisms we use shape our thinking habits, for better or for worse, and that means that we have to be very careful in the choice of what we learn and teach, for unlearning is not really possible. (Many years ago, if I could use a new assistant, one prerequisite would be No prior exposure to FORTRAN", and at high schools in Siberia, the teaching of BASIC was not allowed.) Edsger W. Dijkstra aus E. W. Dijkstra Archive http://www.cs.utexas.edu/~EWD/ 9 Funktionale Programmierung Idee: Programm besteht aus I einer Menge von Funktionsdefinitionen (Termgleichungen) I einem Ausdruck Vorteile: I deklarativ: Jedes funktionale Programm beschreibt ein Problem, nicht dessen Lösung I Funktionen sind Daten (ermöglicht Funktionen höherer Ordnung) I Rein funktionale Programme sind zustandsund damit nebenwirkungsfrei, daher I I I I Korrektheit einfach nachprüfbar (Verifikation) einfache modulare Konstruktion einfach parallelisierbar Programm repräsentiert seine Semantik (ausführbare Spezifikation, geeignet für rapid Prototyping) 10 Geschichte ab ca. 1930 ab ca. 1950 ab ca. 1960 ab ca. 1970 ab 1987 Alonzo Church John McCarthy Peter Landin John Backus Robin Milner David Turner λ-Kalkül LISP ISWIM FP ML Miranda Haskell 11 Warum Haskell? I deklarativ, Nähe zum (mathematischen) Modell I keine Nebenwirkungen (klare Semantik) I Funktionen sind Daten (Funktionen höherer Ordnung) I starkes Typsystem I Typklassen I lazy evaluation (ermöglicht Rechnen mit unendlichen Datenstrukturen) I kompakte Darstellung (kurze Programme) I Modulsystem 12 Entwicklung von Haskell-Programmen Haskell-Interpreter: ghci, Hugs Haskell-Compiler: ghc Entwicklungsumgebungen: I http://leksah.org/ I http://eclipsefp.sourceforge.net/ I http://www.haskell.org/visualhaskell/ alles kostenlos und open source Real Programmers (http://xkcd.com/378/) 13 Haskell-Programme Semantik: Funktion von Eingabe auf Ausgabe I keine Variablen, also keine Programmzustände (kein Aufruf-Kontext) I Wert jeder Funktion(sanwendung) hängt ausschließlich von den Werten der Argumente ab Syntax: I Ausdrücke: Terme z.B. 2 + x * 7 oder double 2 I Funktionsdefinition: Gleichung zwischen zwei Ausdrücken z.B. inc x = x + 1 Programm: I I I Liste von Funktionsdefinitionen Ausdruck 14 Ausdrücke Ausdruck = Term (Baumstruktur) Jeder Ausdruck hat I einen Typ und I einen Wert Berechnung des Wertes durch schrittweise Reduktion (Termersetzung) 15 Beispiele Ausdruck 7 hat I den Typ Int I den Wert 7 Ausdruck 3 * 7 + 2 hat I den Typ Int I den Wert ? Reduktion: rekursive Berechnung des Wertes 16 Funktionsdeklarationen double :: Int -> Int double x = x + x (Typdeklaration) (Funktionsdefinition) Ausdruck double 3 hat I den Typ Int I den Wert 6 Ausdruck double (double 3) hat I den Typ Int I den Wert ? Ausdruck double hat I den Typ Int -> Int I den Wert x 7→ x + x (mathematische Notation) λx.(x + x) (λ-Kalkül) 17 Auswertung Normalform: nicht-reduzierbarer Ausdruck Auswertung: schrittweise Reduktion, bis Normalform erreicht Auswertungsstrategien: innermost-Reduktion (strikt) outermost-Reduktion (lazy) Besonders in Haskell: I Termination I Auswertungsreihenfolge egal (Konfluenz) 18 Definition von Funktionen I Fallunterscheidung I Rekursion Beispiel: fac n = if n < 1 then 1 else n * (fac (n-1)) zum Vergleich: Ablaufsteuerung in imperativen Sprachen I Nacheinanderausführung I Verzweigung I Wiederholung (Iteration) 19 Funktionen als Daten f :: Int -> Int f x = 2 * x + 3 äquivalent: Lambda-Ausdruck f = λx.(2x + 3) Funktionsanwendung (Reduktion): f = λx.A fB = A[x 7→ B] falls x nicht (frei) in B vorkommt Lambda-Kalkül: Alonzo Church 1936, Henk Barendregt 1984, ... Beispiel: A = 2x + 3, B = 1 f = λx.A = λx.(2x + 3) fB = (λx.A)B = λx.(2x + 3)1 = 2·1+3=5 20 Rekursion und Pattern Matching fac :: Int -> Int fac 1 = 1 fac n = n * (fac (n-1)) Wert von fac 4 ? Wert von fac (-4) ? Verbesserungsvorschlag ? alternative Darstellung: fac :: Int -> Int fac n = if (n > 1) then n * (fac (n-1)) else 1 noch viel mehr: http://www.willamette.edu/~fruehr/haskell/ evolution.html 21 Haskell-Datentypen einfache Datentypen, z.B. Int ganze Zahlen (feste Länge) Integer ganze Zahlen (beliebige Länge) Bool Wahrheitswerte Char ASCII-Symbole Konstruktion zusammengesetzter Datentypen: I Produkt, z.B. Tupel I Summe (Fallunterscheidung) z.B. Aufzählungstypen True, False I Rekursion, z.B. Listen, Bäume I Potenz, Funktionen 22 Algebraische Datentypen data Foo = Foo { bar :: Int, baz :: String } deriving Show Bezeichnungen: I data Foo ist Typname I Foo { .. } ist Konstruktor I bar, baz sind Komponenten x :: Foo x = Foo { bar = 3, baz = "hal" } Mathematisch: Produkt Foo = Int × String 23 Datentyp mit mehreren Konstruktoren Beispiel (selbst definiert) data T = A { foo :: Int } | B { bar :: String } deriving Show Beispiel (in Prelude vordefiniert) data Bool = False | True data Ordering = LT | EQ | GT Mathematisch: (disjunkte) Summe Bool = { False } ∪ { True } 24 Fallunterscheidung, Pattern Matching data T = A { foo :: Int } | B { bar :: String } Fallunterscheidung: f :: T -> Int f x = case x of A {} -> foo x B {} -> length $ bar x Pattern Matching (Bezeichner f,b werden lokal gebunden): f :: T -> Int f x = case x of A { foo = f } -> f B { bar = b } -> length b 25 Rekursive Datentypen data Tree = Leaf {} | Branch { left :: Tree, key :: Int , right :: Tree } full :: Int -> Tree -- vollst. binärer Baum full h = if h > 0 then Branch { left = full (h-1) , key = h, right = full (h-1) } else Leaf { } leaves :: Tree -> Int leaves t = case t of Leaf {} -> ... Branch {} -> 0 26 Polymorphie data Tree a = Leaf {} | Branch { left :: Tree a, key :: a , right :: a } inorder :: Tree a -> [ a ] inorder t = case t of ... 27 Listen eigentlich: data List a = Nil {} | Cons { head :: a, tail :: List a } aber aus historischen Gründen data [a] = a : [a] | [] Pattern matching dafür: length :: [a] -> Int length l = case l of [] -> 0 x : xs -> ... Summe der Elemente einer Liste? 28 Peano-Zahlen data Nat = Zero | S Nat Addition add :: Nat -> Nat -> Nat add x Zero = x add x ( S y ) = S ( add x y ) Beispiel: add (S (S (S Zero ))) (S (S Zero)) = S (S (S (S (S Zero)))) Ausführung der Berechnungsschritte (Tafel) Nat ist mit dieser Addition assoziativ, kommutativ, add Zero x = x Nachweis durch strukturelle Induktion (Tafel) Definition weiterer Operationen: Multiplikation, Potenz 29