1 Funktionale vs. Imperative Programmierung 1.1 Einführung Programme einer funktionalen Programmiersprache (functional programming language, FPL) bestehen ausschließlich aus Funktionsdefinitionen und Funktionsaufrufen. Die Bausteine der Funktionsdefinitionen sind dabei der Aufruf weiterer vom Programmierer definierter Funktionen und der Aufruf elementarer Funktionen (und Operatoren), die durch die FPL selbst definiert werden. Anwendung (application) einer Funktion f auf ein Argument e ist das zentrale Konzept in FPLs und wird daher standardmäßig einfach durch Nebeneinanderschreiben (Juxtaposition) notiert: Funktionale Programme werden ausschließlich durch Kompositionen von Funktionsanwendungen konstruiert. f e 2003 T. Grust Funktionale Programmierung: 1. Funktionale vs. Imperative Programmierung 7
Funktionale PL Programmkonstruktion: Applikation und Komposition Operational: Funktionsaufruf, Ersetzung von Ausdrücken Formale Semantik: λ-kalkül Imperative PL Programmkonstruktion: Sequenzen von Anweisungen Operational: Zustandsänderungen (Seiteneffekte) Formale Semantik: schwierig (denotationale Semantiken) FPLs bieten konsequenterweise folgende Konzepte nicht: Sequenzoperatoren für Anweisungen ( ; in Pascal oder C) (Programme werden durch Funktionskomposition zusammengesetzt, eine explizite Reihung von Anweisungen existiert nicht) Zustand (FPLs sind zustandslos und bieten daher keine änderbaren Variablen) Zuweisungen ( := in Pascal) (Berechnungen in FPLs geschehen allein durch Auswertung von Funktionen, nicht durch Manipulation des Maschinenzustandes bzw. -speichers) 2003 T. Grust Funktionale Programmierung: 1. Funktionale vs. Imperative Programmierung 8
Beispiel 1.1 Entwerfe eine Funktion, die testet, ob eine Zahl n eine Primzahl ist oder nicht. 1 Wenn n prim ist, ist die Menge der Teiler (factors) von n leer. 2 Die Menge der Teiler von n sind alle Zahlen x zwischen 2... n 1, die n ohne Rest teilen. Diese Beschreibung der Eigenschaften einer Primzahl läßt sich direkt in ein funktionales Programm (hier: Haskell) übersetzen: -- Ist n eine Primzahl? isprime :: Integer -> Bool isprime n = (factors n == []) -- 1 where factors n = [ x x <- [2..n-1], n mod x == 0 ] -- 2 Das Programm liest sich mehr wie die deklarative Spezifikation der Eigenschaften einer Primzahl als eine explizite Vorschrift, den Primzahltest auszuführen. Bspw. ist eine parallele Ausführung von factors nicht ausgeschlossen. 2003 T. Grust Funktionale Programmierung: 1. Funktionale vs. Imperative Programmierung 9
Imperative Programmiersprachen sind dagegen eng mit dem zugrundeliegenden von Neumann schen Maschinenmodell verknüpft, indem sie die Maschinenarchitektur sehr direkt abstrahieren: der Programmzähler (PC) der CPU arbeitet Anweisung nach Anweisung sequentiell ab (der Programmierer hat seine Anweisungen also explizit aufzureihen und Wiederholungen/Sprünge zu codieren) der Speicher der Maschine dient zur Zustandsprotokollierung (der Zustand eines Algorithmus muß durch Variablenzuweisung bzw. -auslesen explizit kontrolliert werden) Zusätzlich zur Lösung seines Problemes hat der Programmierer einer imperativen PL die Aufgabe, obige Punkte korrekt zu spezifizieren. Imperative Programme sind oft länger als ihre FPL-Äquivalente, (Zustandsupdates und -kontrollen sind explizit zu codieren) sind oft schwieriger zu verstehen, (eigentliche Problemlösung und Kontrolle der von Neumann-Maschine werden vermischt) sind nur mittels komplexer Methoden auf Korrektheit zu überprüfen. (Bedeutung jedes Programmteils immer von Zustand des gesamten Speichers und Änderungen auf diesem abhängig) 2003 T. Grust Funktionale Programmierung: 1. Funktionale vs. Imperative Programmierung 10
Beispiel 1.2 Primzahltest. Formulierung in PASCAL: program isprime (output); function isprime (n : integer) : boolean; var m : integer; found_factor : boolean; begin m := 2; found_factor := false; while (m <= n-1) and (not found_factor) do if (n mod m) = 0 then found_factor := true else m := m + 1; isprime := not found_factor end; { isprime } begin writeln (isprime(112)) end. 2003 T. Grust Funktionale Programmierung: 1. Funktionale vs. Imperative Programmierung 11
Das Programm kontrolliert die Maschine durch explizite Schleifenanweisungen (while, for), bedingte Anweisungen (if then else) und Sequenzierung ( ; ) von Anweisungen. Die Anweisungsfolge ist explizit festgelegt. Das ist das Hauptmerkmal des imperativen Stils. Die Berechnung erfolgt als Seiteneffekt auf den Zustandsvariablen (m, found_factor). Die Variablen dienen gleichzeitig zur Kontrolle der Maschine (m, found_factor) und zur Protokollierung des Ergebnisses des eigentlichen Problems (found_factor). Andere Konzepte imperativer PLs bieten noch weitergehenden direkten Zugriff auf die Maschine: Arrays und Indexzugriff (A[i]) (modelliert direkt den linearen Speicher der Maschine sowie indizierende Adressierungsmodi der CPU) Pointer und Dereferenzierung (modellieren 1:1 die indirekten Adressierungsmodi der CPU) explizite (De-)Allokation von Speicher (malloc, free, new) (der Speicher wird eigenverantwortlich als Resource verwaltet) Sprunganweisungen (goto)... (direkte Manipulation des PC) 2003 T. Grust Funktionale Programmierung: 1. Funktionale vs. Imperative Programmierung 12