1 Funktionale vs. Imperative Programmierung 1.1 Einführung

Werbung
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
I der Aufruf weiterer vom Programmierer definierter Funktionen und
I 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:
f e
Funktionale Programme werden ausschließlich durch Kompositionen von Funktionsanwendungen
konstruiert.
© 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:
I Sequenzoperatoren für Anweisungen (‘;’ in Pascal oder C)
(Programme werden durch Funktionskomposition zusammengesetzt, eine explizite Reihung von Anweisungen
existiert nicht)
I Zustand
(FPLs sind zustandslos und bieten daher keine änderbaren Variablen)
I 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.
O
1 Wenn n prim ist, ist die Menge der Teiler (factors) von n leer.
O
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 == [])
where
factors n = [ x | x <- [2..n-1], n ‘mod‘ x == 0 ]
1
-- O
2
-- O
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:
I 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)
I 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
I sind oft länger als ihre FPL-Äquivalente,
(Zustandsupdates und -kontrollen sind explizit zu codieren)
I sind oft schwieriger zu verstehen,
(eigentliche Problemlösung und Kontrolle der von Neumann-Maschine werden vermischt)
I 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:
I Arrays und Indexzugriff (A[i])
(modelliert direkt den linearen Speicher der Maschine sowie indizierende Adressierungsmodi der CPU)
I Pointer und Dereferenzierung
(modellieren 1:1 die indirekten Adressierungsmodi der CPU)
I explizite (De-)Allokation von Speicher (malloc, free, new)
(der Speicher wird eigenverantwortlich als Resource verwaltet)
I Sprunganweisungen (goto)
(direkte Manipulation des PC)
I ...
© 2003 T. Grust · Funktionale Programmierung: 1. Funktionale vs. Imperative Programmierung
12
Herunterladen