65
Funktionale Programmierung Klaus Becker 2014

Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

Embed Size (px)

Citation preview

Page 1: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

Funktionale Programmierung

Klaus Becker

2014

Page 2: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

2 Funktionale Programmierung

Page 3: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

3 Teil 1

Warum funktional programmieren?

Page 4: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

4 Ausgangspunkt – die Maschine

Bei der Entwicklung von Programmiersprachen stand zu Beginn die Steuerung der realen Hardware im Mittelpunkt. Mit einem überschaubaren Befehlssatz konnte man direkt die benutzte „Hardware-Maschine“ programmieren.

org 100h start: mov dx,meldung1 mov ah,9h int 021h mov ah, 01h ;Wert über die Tastatur einlesen int 021h cmp al, '5' jne ende mov dx,meldung2 mov ah,9h int 021h ende: mov ah,4Ch int 21h section .data meldung1: db 'Bitte geben Sie eine Zahl ein:', 13, 10, '$' meldung2: db 13, 10, 'Sie haben die Zahl 5 eingegeben.', 13, 10, '$'

Wir orientieren uns im Folgenden nicht an realer Hardware, sonderrn benutzen mit der Registermaschine ein einfaches Maschinenmodell.

Page 5: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

5 Registermaschine

Registermaschinen enthalten einen Speicher, der aus einzelnen, durchnummerierten Registern besteht, in denen natürliche Zahlen gespeichert werden können.

> x INC i Erhöhe Register i um 1. Gehe zu Zeile x+1.

> x DEC i Erniedrige Register i um 1. Gehe zu Zeile x+1.

> x JMP i Gehe zu Zeile i.

> x TST iWenn Register i ungleich 0 ist, dann gehe zu Zeile x+1, sonst zu Zeile x+2.

> x HLT Beende die Bearbeitung.

> 0 TST 1 1 JMP 3 2 JMP 6 3 DEC 1 4 INC 0 5 JMP 0 6 HLT

5

3

0

...

0

1

2

...

Zur Steuerung der Registermaschinen gibt es eine einfache maschinennahe Programmiersprache, die nur die folgenden 5 Befehle kennt:

Page 6: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

6 Programmanalyse

Aufgabe

(a) Kannst du auf den ersten Blick erkennen, was das gezeigte Registermaschinenprogramm leistet?

(b) Führe das Programm aus. Gehe von der folgenden Anfangsbelegung der Register aus:

{R0: 0; R1: 4; R2:6; R3:0; ...}.

Weißt du jetzt, was das Programm leistet? Wenn nicht, dann führe weitere Tests durch.

(c) Warum ist es so schwer zu erkennen, was das Programm leistet?

0 TST 11 JMP 32 JMP 63 TST 24 JMP 125 JMP 96 TST 27 JMP 188 HLT9 TST 110 JMP 1611 HLT 12 DEC 113 DEC 214 INC 015 JMP 016 DEC 117 JMP 918 DEC 219 JMP 6

Page 7: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

7 Spaghetti-Code

Maschinennahe Programmiersprachen nutzen Sprungbefehle (wie z.B. JMP), um Wiederholungen zu realisieren.

0 TST 11 JMP 32 JMP 63 TST 24 JMP 125 JMP 96 TST 27 JMP 188 HLT9 TST 110 JMP 1611 HLT 12 DEC 113 DEC 214 INC 015 JMP 016 DEC 117 JMP 918 DEC 219 JMP 6

0 TST 11 JMP 32 JMP 63 TST 24 JMP 125 JMP 96 TST 27 JMP 188 HLT9 TST 110 JMP 1611 HLT 12 DEC 113 DEC 214 INC 015 JMP 016 DEC 117 JMP 918 DEC 219 JMP 6

Sprungbefehle können leicht dazu führen, dass Programme völlig undurchschaubar werden. Im gezeigten Programm führen die Sprungbefehle zu einer Art Spaghetti-Code, bei dem die Ablauflogik nicht leicht zu entwirren ist.

Ablaufmodellierung mit Sprungbefehlen Spaghetti-Code

Page 8: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

8 Verzicht auf Sprungbefehle

Schon früh erkannte man die Schwäche von Sprungbefehlen und versucht seither, auf höheren Programmierebenen möglichst auf die Verwendung solcher Befehle zu verzichten.

Strukturierte Programmierung benutzt keine Sprungbefehle zur Ablaufmodellierung, sondern Kontrollstrukturen, die bestimmte Ablaufmuster vorgeben.

while (R1 != 0) and (R2 != 0): R0 = R0 + 1 R1 = R1 - 1 R2 = R2 - 1while R1 != 0: R1 = R1 - 1while R2 != 0: R2 = R2 - 1

Im Programm wird die Kontrollstruktur "Wiederholung mit Eintrittsbedingung" (dargestellt durch eine while-Schleife) zur Modellierung benutzt.

Kontrollstrukturen erhöhen die Transparenz der Ablauflogik und verringern die Fehlerquote bei der Entwicklung von Programmen.

Im Programm wird die Kontrollstruktur "Wiederholung mit Eintrittsbedingung" (dargestellt durch eine while-Schleife) zur Modellierung benutzt.

Kontrollstrukturen erhöhen die Transparenz der Ablauflogik und verringern die Fehlerquote bei der Entwicklung von Programmen.

Ablaufmodellierung mit Kontrollstrukturen

Page 9: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

9 Prozeduren

Als Weiterentwicklung von hardwareorientierten Programiersprachen können die prozeduralen Programmiersprachen angesehen werden. Hier können Sequenzen von Anweisungen zu Prozeduren zusammengefasst werden, die dann als Befehle für eine abstraktere, hypothetische Maschine gedeutet werden können.

program bsp ! implicit none real :: x, y, z write( *, * ) 'x -> ' read( *, * ) x call sub( x, y, z ) write( *, * ) 'y -> ', y, 'z -> ', zend

subroutine sub( a, b, c ) ! implicit none real :: a, b, c b = a**2 c = a**2 + bend subroutine sub

Page 10: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

10 Programmanalyse

Aufgabe

(a) Was leistet die Prozedur minimum?

(b) Ergänze den Python-Dialog.

(c) Was ist an der gezeigten Vorgehensweise problematisch?

def minimum(a, b): global m while (a != 0) and (b != 0): m = m + 1 a = a - 1 b = b - 1

>>> m = 0>>> minimum(5, 8)>>> m

>>> minimum(7, 2)>>> m

Page 11: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

11 Seiteneffekte

Das Unterprogramm auf der linken Seite verändert den Wert einer globalen Variablen. Das Unterprogramm hat einen sog. Seiteneffekt.

>>> m = 0>>> minimum(5, 8)>>> m5>>> minimum(7, 2)>>> m7

Unterprogramm mit Seiteneffekt

def minimum(a, b): global m while (a != 0) and (b != 0): m = m + 1 a = a - 1 b = b - 1

Seiteneffekte führen dazu, dass das Verhalten von Funktionen schwer zu durchschauen ist. Insbesondere bei komplexeren Programmen verliert man leicht den Überblick, welche (beabsichtigten und auch unbeabsichtigten) Nebenwirkungen ein Funktionsaufruf mit Seiteneffekten hat. Man versucht daher, Seiteneffekte möglichst zu vermeiden.

Page 12: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

12 Vermeidung von Seiteneffekten

Eine Möglichkeit besteht darin, die Verantwortung für seiteneffektfreie Programme dem Programmentwickler zu überlassen. Dieser muss dann dafür Sorge tragen, dass keine Bausteine mit Seiteneffekten erstellt werden.

Eine andere Möglichkeit besteht darin, die Programmiersprache so zu konzipieren, dass keine Seiteneffekte mehr möglich sind.

Funktionale Programmierung ist (zumindest in der strengen Version) so konzipiert, dass keine Seiteneffekte auftreten können und dass referentielle Transparenz stets gewährleistet ist.

Page 13: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

13 Referentielle Transparenz

>>> minimum(5, 8)5>>> minimum(5, 8)5

>>> m = 0>>> minimum(5, 8)>>> m5>>> minimum(5, 8)>>> m10

Unterprogramm mit Seiteneffekt

def minimum(a, b): m = 0 while (a != 0) and (b != 0): m = m + 1 a = a - 1 b = b - 1 return m

def minimum(a, b): global m while (a != 0) and (b != 0): m = m + 1 a = a - 1 b = b – 1

Funktion ohne Seiteneffekt

Referentielle Transparenz liegt vor, wenn ein Teilausdruck - unabhängig von seiner Position innerhalb eines Ausdrucks und unabhängig vom Zeitpunkt der Auswertung - immer denselben Wert hat.

keine referentielle Transparenz

Page 14: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

14 Dialog über SeiteneffekteI: Hallo! Ich vertrete hier die imperative Programmierung.

F: Hallo, und ich vertrete die funktionale Programmierung.

I: Stimmt es, dass du keine Seiteneffekte erlaubst?

F: Ja, so ist es.

I: Und wie machst du das?

F: Seiteneffekte entstehen durch Zuweisungen an globale Variablen. Bei mir gibt es gar keine Zuweisungen mehr. Dann kann man auch nicht in die Verlegenheit kommen, einer globalen Variablen etwas zuzuweisen.

I: Klingt einfach. Aber, wie soll man dann einen so einfachen Vorgang wie den folgenden ohne Zuweisungen beschreiben?

F: Man muss es halt ganz anders machen.

I: Das kann ich mir nicht so recht vorstellen. Wenn es keine Zuweisungen gibt, dann macht es auch keinen großen Sinn, Variablen einzuführen. Man hat ja keine Möglichkeit, den Wert der Variablen zu verändern. Und wenn man Werte von Variablen nicht verändern kann, dann kann man es durch Anweisungen im Schleifenkörper auch nicht erreichen, dass die Abbruchbedingung einer SOLANGE-Schleife erfüllt wird. Das macht ja alles keinen Sinn mehr.

F: Wieso bist du so auf Variablen und Schleifen fixiert?

I: Variablen benötigt man ja wohl zur Datenverwaltung und ohne Schleifen gibt es keine Wiederholungen. Oder sehe ich das ganz falsch?

F: Ja, das siehst du etwas zu eng. Wenn du wissen willst, wie mein Berechnungskonzept funktioniert, dann musst du dir den nächsten Abschnitt anschauen.

ALGORITHMUS Summenberechnung:{vorher: n aus N}setze s auf 0setze i auf 0SOLANGE i <= n: erhöhe s um i erhöhe i um 1{nachher: s = 0+1+2+...+n}

Page 15: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

15 Exkurs: Seiteneffekte bei Objektendef invertiereBild(L): """ das in L dargestellte Bild wird invertiert d.h.: aus 0 wird 1 und aus 1 wird 0 """ for i in range(3, len(L)): if L[i] == 0: L[i] = 1 else: L[i] = 0 return L

def addBit(i, j): """ die Bits i, j werden add.: 0+0->0;0+1->1;1+0->1;1+1->1 """ s = i+j if s == 2: s = 1 return s

def addBilder(M, N): """ die Bitfolgen in M und N werden Bit für Bit addiert """ L = [] for i in range(len(M)): if i < 3: L = L + [M[i]] else: L = L + [addBit(M[i], N[i])] return L

Page 16: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

16 Exkurs: Seiteneffekte bei Objekten>>> bild = ['P1', 3, 3, 1, 1, 1, 1, 0, 1, 1, 1, 1]>>> negativ = invertiereBild(bild)>>> negativ['P1', 3, 3, 0, 0, 0, 0, 1, 0, 0, 0, 0]>>> neuesBild = addBilder(bild, negativ)>>> neuesBild???

Aufgabe:

Was erwartest du als Ergebnis beim Testdialog? Warum erhält man ein anderes Ergebnis?

Aufgabe:

Was erwartest du als Ergebnis beim Testdialog? Warum erhält man ein anderes Ergebnis?

Page 17: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

17 Teil 2

Funktionen als Programmierbausteine

Page 18: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

18 Datenverarbeitung mit Funktionen

def bmi(gewicht, groesse): return \ gewicht/(groesse*groesse)

Beispiel: BMI-Berechnung

# Eingabegewicht = float(input("..: "))groesse = float(input("..: "))# Verarbeitungbmi = gewicht / (groesse * groesse)# Ausgabeprint("BMI:", bmi)

>>> Gewicht in kg: 70Größe in m: 1.70BMI: 24.2214532872

>>> bmi(70, 1.70)24.221453287197235

Eingabe der Daten Übergabe der Daten

Ausgabe der Daten

Rückgabe der Daten

Wir ersetzen die Eingabe von Daten (durch einen Benutzer) durch die abstraktere Datenübergabe und die Ausgabe der Daten (auf dem Bildschirm) durch die abstraktere Datenrückgabe und konzentrieren uns stärker auf die Verarbeitung der Daten.

Page 19: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

19 Funktionale Programme

def bmi(gewicht, groesse): return \ gewicht/(groesse*groesse)

Eine Funktion ist eine Einheit, die übergebene Daten verarbeitet und den berechneten Funktionswert als Ergebnis zurückgibt. Die Verarbeitung wird über eine Funktionsdefinition (man sagt oft auch Funktionsdeklaration) festgelegt. Aktiviert wird eine Verarbeitung durch einen Funktionsaufruf.

>>> bmi(70, 1.70)24.221453287197235

Funktiondefinition

FunktionsaufrufEin funktionales Programm besteht aus einer oder mehrerer Funktionsdefinitionen und einem Funktionsaufruf.Eine Funktionsdefinition leistet folgende Festlegungen: die Festlegung der Datenübergabe mit Hilfe von Parameter, die Festlegung der Datenverarbeitung und die Festlegung der Datenrückgabe.

Bei einem Funktionsaufruf werden die Parameter mit konkreten Werten versehen. Diese Daten werden dann nach den Festlegungen in der Funktionsdefinition verarbeitet. Abschließend wird ein Funktionswert als Ergebnis zurückgeliefert.

Page 20: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

20 Funktionale Programme

In einem rein funktionalen Programm dürfen in den Funktionsdefinitionen außer den Parametern keine weiteren Variablen vorkommen.

In der Funktionsdefinition kommen dann auch keine Zuweisungen vor. Hierdurch wird gewährleistet, dass keine Seiteneffekte zustande kommen können.

def wegberechnungen(geschwindigkeit): return ((geschwindigkeit/10)*3, (geschwindigkeit/10)**2, (geschwindigkeit/10)*3 + (geschwindigkeit/10)**2)

rein funktionales Programm

Schwierigkeit:

Teilausdrücke wie (geschwindigkeit/10)*3 und (geschwindigkeit/10)**2 kommen mehrfach in der Berechnungsvorschrift vor und müssen bei der Ausführung gegebenenfalls mehrfach berechnet werden. Das ist ineffizient.

Page 21: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

21 Lokale Bindungen

def wegberechnungen(geschwindigkeit): reaktionsweg = (geschwindigkeit/10)*3 bremsweg = (geschwindigkeit/10)**2 anhalteweg = reaktionsweg + bremsweg return (reaktionsweg, bremsweg, anhalteweg)

Ein Ausweg ergibt sich, wenn wir Variablen als lokale Konstanten verwenden. Das bedeutet, dass Variablen nur lokal innerhalb von Funktionsdefinitionen vorkommen dürfen und dass ihnen nur ein einziges mal ein Wert zugewiesen werden darf. Auf der rechten Seite einer Zuweisung darf dann die Variable, die auf der linken Seite der Zuweisung steht, nicht vorkommen. Man spricht in diesem Zusammenhang auch von lokalen Bindungen.

def wegberechnungen(geschwindigkeit): return ((geschwindigkeit/10)*3, (geschwindigkeit/10)**2, (geschwindigkeit/10)*3 + (geschwindigkeit/10)**2)

keine (neuen) Variablen

nur lokale Bindungen

Page 22: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

22 Lokale Bindungen

def wegberechnungen(geschwindigkeit): reaktionsweg = (geschwindigkeit/10)*3 bremsweg = (geschwindigkeit/10)**2 anhalteweg = reaktionsweg + bremsweg return (reaktionsweg, bremsweg, anhalteweg)

Mit lokalen Bindungen wird ein Term lokal (d.h. innerhalb der Funktionsdefinition) an einen Namen gebunden, so dass man diesen Namen an Stelle des Terms benutzen kann. Funktionale Programme mit lokalen Bindungen kann man also jederzeit in streng funktionale Programme umwandeln, ohne das Verhalten des Programms zu verändern. Evtl. wird nur die Berechnungszeit hierdurch beeinflusst. Funktionale Programme mit lokalen Bindungen erzeugen also keine Seiteneffekte und sind - genau wie rein funktionale Programme - referentiell transparent.

def wegberechnungen(geschwindigkeit): return ((geschwindigkeit/10)*3, (geschwindigkeit/10)**2, (geschwindigkeit/10)*3 + (geschwindigkeit/10)**2)

keine (neuen) Variablen

nur lokale Bindungen

Page 23: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

23 Funktionskomposition

def erstesZeichen(wort): return wort[0]

def ohneErstesZeichen(wort): return wort[1:] def mitLetztemZeichen(wort, \ zeichen): return wort + zeichen

Beispiel: erstes Zeichen eines Wortes ans Ende verschieben

# Eingabewort = input('Wort: ')# Verarbeitung# entferne das erste ZeichenerstesZeichen = wort[0]wort = wort[1:]# füge es am Ende des Worts einwort = wort + erstesZeichen# Ausgabeprint(wort)

mehrere Aktionen hintereinander ausführen

>>> mitLetztemZeichen(ohneErstesZeichen('TOR'), erstesZeichen('TOR'))

'OR' 'T'

'ORT'

Funktionsaufrufe ineinander schachteln

Page 24: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

24 Funktionskomposition

def erstesZeichen(wort): return wort[0]

def ohneErstesZeichen(wort): return wort[1:] def mitLetztemZeichen(wort, zeichen): return wort + zeichen

def erstesZeichenAlsLetztesZeichen(wort): return mitLetztemZeichen(ohneErstesZeichen(wort), \ erstesZeichen(wort))

Beispiel: Zeichen innerhalb eines Wortes verschiebenBei der Komposition bzw. Verkettung von Funktionen werden Funktionen ineinandergeschachtelt aufgerufen.

Aufgabe: Löse die Probleme in (a) und (b) analog mit einer Funktion, die geeignete Hilfsfunktionen benutzt.

(a) In einer nicht-leeren Zeichenkette soll das letzte Element ganz an an den Anfang der Zeichenkette gesetzt werden. Aus 'ORT' soll so 'TOR' erzeugt werden.

(b) In einer nicht-leeren Zeichenkette soll das erste mit dem letzten Zeichen ausgetauscht werden. Aus 'TOR' soll so 'ROT' erzeugt werden.

Page 25: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

25 Fallunterscheidungen

def ohneErstesZeichen(wort): if wort != '': return wort[1:] else: return ''

Beispiel: erstes Zeichen eines Wortes entfernen

WENN das Wort Zeichen enthält: entferne das erste ZeichenSONST: tue nichts

Fallunterscheidung

Funktionsdefinition mit Fallunterscheidung

Bei einer Funktionsdefinition mit Fallunterscheidung werden die Funktionswerte für verschiedene Fälle (evtl. unterschiedlich) festgelegt.

Aufgabe: Löse die folgenden Probleme mit geeigneten Hilfsfunktionen. Dabei soll auch berücksichtigt werden, dass das Ausgangswort eventuell keine Zeichen enthält.

(a) In einer nicht-leeren Zeichenkette soll das letzte Element ganz an an den Anfang der Zeichenkette gesetzt werden. Aus 'ORT' soll so 'TOR' erzeugt werden.

(b) In einer nicht-leeren Zeichenkette soll das erste mit dem letzten Zeichen ausgetauscht werden. Aus 'TOR' soll so 'ROT' erzeugt werden.

Page 26: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

26 Wiederholungen

Eingabe: wortaltesWort = wortneuesWort = ''SOLANGE altesWort noch Zeichen enthält: füge das erste Zeichen von altesWort vorne in neuesWort ein entferne das erste Zeichen von altesWortAusgabe: neuesWort

Beispiel: Wörter umdrehen

{neuesWort -> ''; altesWort -> 'LEBEN'}neuesWort = altesWort[0] + neuesWortaltesWort = altesWort[1:]{neuesWort -> 'L'; altesWort -> 'EBEN'}neuesWort = altesWort[0] + neuesWortaltesWort = altesWort[1:]{neuesWort -> 'EL'; altesWort -> 'BEN'}neuesWort = altesWort[0] + neuesWortaltesWort = altesWort[1:]{neuesWort -> 'BEL'; altesWort -> 'EN'}neuesWort = altesWort[0] + neuesWortaltesWort = altesWort[1:]{neuesWort -> 'EBEL'; altesWort -> 'N'}neuesWort = altesWort[0] + neuesWortaltesWort = altesWort[1:]{neuesWort -> 'NEBEL'; altesWort -> ''}

iterativer Lösungsansatz (benutzt Variablen und eine Schleife)

Page 27: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

27 Rekursion

Beispiel: Wörter umdrehen

umdrehen('LEBEN') ->

(umdrehen('EBEN') + 'L') ->

((umdrehen('BEN') + 'E') + 'L') ->

(((umdrehen('EN') + 'B') + 'E') + 'L') ->

((((umdrehen('N') + 'E') + 'B') + 'E') + 'L') ->

(((((umdrehen('') + 'N') + 'E') + 'B') + 'E') + 'L') ->

((((('' + 'N') + 'E') + 'B') + 'E') + 'L') ->

(((('N' + 'E') + 'B') + 'E') + 'L') ->

((('NE' + 'B') + 'E') + 'L') ->

(('NEB' + 'E') + 'L') ->

('NEBE' + 'L') ->

'NEBEL'

rekursiver Lösungsansatz (benutzt Problemreduktionen und

Funktionskomposition)

Page 28: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

28 Rekursion

Beispiel: Wörter umdrehen

umdrehen('LEBEN') ->

(umdrehen('EBEN') + 'L') ->

((umdrehen('BEN') + 'E') + 'L') ->

(((umdrehen('EN') + 'B') + 'E') + 'L') ->

((((umdrehen('N') + 'E') + 'B') + 'E') + 'L') ->

(((((umdrehen('') + 'N') + 'E') + 'B') + 'E') + 'L') ->

((((('' + 'N') + 'E') + 'B') + 'E') + 'L') ->

(((('N' + 'E') + 'B') + 'E') + 'L') ->

((('NE' + 'B') + 'E') + 'L') ->

(('NEB' + 'E') + 'L') ->

('NEBE' + 'L') ->

'NEBEL'

Problemreduktionsmuster:

Fall 1: wort == ''umdrehen(wort) -> wortFall 2: wort != ''umdrehen(wort) -> umdrehen(wort[1:]) + wort[0]

def umdrehen(wort): if len(wort) == 0: return '' else: return umdrehen(wort[1:]) + wort[0]

rekursive Funktionsdefinition

Page 29: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

29 Rekursion

Rekursive Problemreduktion ist eine Problemlösestrategie, bei der ein Problem auf ein strukturgleiches Problem (in "verkleinerter" Form) zurückgeführt wird.

Eine rekursive Funktionsdefinition ist eine Funktionsdefinition, bei der die Funktion selbst im Funktionsterm benutzt wird.

def umdrehen(wort): if len(wort) == 0: return wort else: return umdrehen(wort[1:]) + wort[0]

Page 30: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

30

Ausführung rekursiver Funktionsdef.

Bei der Auswertung von Funktionsaufrufen kommt es bei rekursiven Funktionsdefinitionen zur wiederholten Ausführung strukturgleicher Reduktionsschritte. Rekursion kann somit als Ersatz für die Kontrollstruktur "Wiederholung" benutzt werden.

Damit dieses Wiederholungskonzept terminiert, muss nach endlichen vielen Reduktionsschritten eine Situation erreicht werden, bei der die Lösung zum Problem direkt angegeben werden kann. Man versucht daher, Reduktionsschritte so zu konzipieren, dass sie das Problem in einer Weise "verkleinern", die nur endlich viele Verkleinerungsschritte zulässt.

Rekursion ist eine mächtige und gerne genutzte Strategie beim Problemlösen. Wenn der Problemkontext es zulässt, dann kann man das Problemlöseverfahren sehr einfach und kompakt über eine Problemreduktion beschreiben. Die wiederholte Ausführung der Reduktionsschritte - und damit die Erzeugung der Lösung - überlässt man dem Ausführsystem.

umdrehen('LEBEN') ->(umdrehen('EBEN') + 'L') ->((umdrehen('BEN') + 'E') + 'L') ->(((umdrehen('EN') + 'B') + 'E') + 'L') ->((((umdrehen('N') + 'E') + 'B') + 'E') + 'L') ->(((((umdrehen('') + 'N') + 'E') + 'B') + 'E') + 'L') ->((((('' + 'N') + 'E') + 'B') + 'E') + 'L') ->(((('N' + 'E') + 'B') + 'E') + 'L') ->((('NE' + 'B') + 'E') + 'L') ->(('NEB' + 'E') + 'L') ->('NEBE' + 'L') ->'NEBEL'

Page 31: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

31 Modularisierung

Fazit:

Funktionale Programmierung setzt konsequent das Modularisierungsprinzip um. Modularisierung bedeutet, ein Gesamtsystem nach dem Baukastenprinzip aus Einzelbausteinen (den sogenannten "Modulen") zusammenzusetzen. Funktionen können als Bausteine angesehen werden, die man mit Hilfe von Funktionskomposition flexibel zusammensetzen kann. Wenn sie - wie in der funktionalen Programmierung üblich - frei von Seiteneffekten konzipiert werden, dann können die Bausteine unabhängig genutzt werden.

Page 32: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

32 Aufgaben

Aufgabe:

Wir betrachten die Berechnung der Summe natürlicher Zahlen.

ALGORITHMUS Summenberechnung:{vorher: n aus N}setze s auf 0setze i auf 0SOLANGE i <= n: erhöhe s um i erhöhe i um 1{nachher: s = 0+1+2+...+n}

Regeln Summenberechnung:

summe(0) ->

0

summe(5) ->

5 + summe(4)

iterative Lösung rekursive Lösung

Entwickle und teste eine hierzu passende Funktionsdefinition.

Page 33: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

33 Aufgaben

Aufgabe:

Ein Kapital von 1000 Euro wird jährlich mit 5% verzinst. Die Funktion kapital(n) beschreibe den Kapitalwert nach n Jahren.

Die folgenden Problemreduktionsschritte sollen einem funktionalen Programm zu Grunde liegen.

Verallgeinere diese Reduktionsschritte zu einem Programm und teste es mit mehreren Funktionsaufrufen.

kapital(0) ->

1000

kapital(5) ->

kapital(4) + 0.05 * kapital(4)

Page 34: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

34 Aufgaben

Aufgabe:

Ein Patient nimmt jeden Morgen 5 mg eines Medikaments ein. Im Laufe des Tages werden von dem gesamten, im Körper befindlichen Medikament 40% abgebaut. Die Funktion medikamentenmenge(n) beschreibe die Menge des Medikaments (in mg), die sich am n-ten Tag morgens nach Einnahme des Medikaments im Körper befindet.

Ergänze die folgenden Problemreduktionsschritte und verallgemeinere sie zu einem funktionalen Programm.

medikamentenmenge(0) ->

...

medikamentenmenge(5) ->

...

Page 35: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

35 Aufgaben

Aufgabe:

Was leistet die folgendermaßen definierte Funktion?

Teste diese Funktion mit verschiedenen Aufrufen und erkläre, wie die Ergebnisse zustande kommen.

def anzahl(element, liste): if len(liste) == 0: return 0 else: if liste[0] == element: return (1 + anzahl(element, liste[1:])) else: return anzahl(element, liste[1:])

Page 36: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

36 Aufgaben

Aufgabe:

Das Problem besteht darin, ein Element aus einer Liste zu entfernen. Kommt das Element mehrfach vor, so soll nur das erste / alle vorkommende Element entfernt werden. Die folgenden Problemreduktionsschritte sollen den funktionalen Programmen zu Grunde liegen. entferneErstes('b', []) -> []

entferneErstes('b', ['b', 'c', 'b']) -> ['c', 'b']

entferneErstes('b', ['a', 'd', 'b', 'c', 'b']) -> ['a'] + entferneErstes('b', ['d', 'b', 'c', 'b'])

entferneAlle('b', []) ->

entferneAlle('b', ['b', 'c', 'b']) ->

entferneAlle('b', ['a', 'd', 'b', 'c', 'b']) ->

Page 37: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

37 Aufgaben

Aufgabe:

Das Problem besteht darin, jedes Element aus einer Zahleniste um einen bestimmten Wert zu erhöhen.

Ergänze die folgenden Problemreduktionsschritte und verallgemeinere sie zu einem funktionalen Programm.

addiere(3, []) ->

addiere(3, [4, 6, 6, 2, 0, 3]) ->

Page 38: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

38 Aufgaben

Aufgabe:

Das Problem besteht darin, aus einer Zahlenliste alle Elemente herauszufiltern, die kleiner als ein bestimmter Wert sind.

Erstelle erst einmal geeignete Problemreduktionsschritte. Verallgemeinere sie anschließend zu einem funktionalen Programm.

Page 39: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

39 Teil 3

Funktionen als Datenobjekte

Page 40: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

40 Datensätze sortieren

Im Sportverein werden die Daten der Mitglieder mit einem Programm verwaltet. Für jedes Mitglied liegt ein Datensatz vor, der z.B. Vorname, Nachname, Geburtsdatum etc. enthält.

Programme zur Verwaltung solcher Daten bieten in der Regel eine Sortierfunktion an. Mit Hilfe der Sortierfunktion können die Daten für bestimmte Zwecke umsortiert werden, z.B. nach Name und Vorname oder nach dem Geburtsdatum.

Page 41: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

41 Datensätze sortieren

Es gibt eine Reihe von Sortierverfahren zur Realisierung der Sortierfunktion. Wir betrachten im Folgenden das Sortieren durch Einfügen.

def einfuegen(e, L): if len(L) == 0: return [e] else: if e < L[0]: return [e] + L else: return [L[0]] + einfuegen(e, L[1:])

def sortieren(L): if len(L) == 0: return [] else: return einfuegen(L[0], sortieren(L[1:]))

Sortieren durch Einfügen

Page 42: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

42

def einfuegen(e, L): if len(L) == 0: return [e] else: if e[1] < L[0][1] or (e[1] == L[0][1] and e[0] < L[0][0]): return [e] + L else: return [L[0]] + einfuegen(e, L[1:])

def sortieren(L): if len(L) == 0: return [] else: return einfuegen(L[0], sortieren(L[1:]))

Datensätze sortierendef einfuegen(e, L): if len(L) == 0: return [e] else: if e[1] < L[0][1]: return [e] + L else: return [L[0]] + einfuegen(e, L[1:])

def sortieren(L): if len(L) == 0: return [] else: return einfuegen(L[0], sortieren(L[1:]))

personendaten = [ ('Britta', 'Koch', (23,5,1995)), ('Paul', 'Schwarz', (11,11,2003)), ('Silke', 'Schmidt', (13,7,1990)), ('Jennifer', 'Abel', (15,12,1993)), ('Adriana', 'Müller', (21,1,2001)), ('Tobias', 'Klein', (1,3,1997)), ('Philipp', 'Bach', (21,4,1997)), ('Oliver', 'Schmitt', (14,4,1994)), ('Simone', 'Schuster', (20,12,2000)), ('Pia', 'Schwarz', (11,11,2003)), ('Andreas', 'Beyer', (16,3,1988)), ('Alexander', 'Heinrich', (17,3,1999)), ('Maximilian', 'Meyer', (21,6,1986))]

Alphabetische Sortierung nach dem Nachnamen

Alphabetische Sortierung nach dem Nach- und Vornamen

Sortierung nach dem Geburtsdatum?

Page 43: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

43 Flexible Vergleiche

einfuegen

[('Andreas', 'Beyer', (16,3,1988)), ...]

[('Andreas', 'Beyer', ...), ..., ('Pia', 'Schwarz', ...), ...]

('Pia', 'Schwarz', (11,11,2003))

L

e

kleinerNachname vergleich

einfuegen

[('Andreas', 'Beyer', (16,3,1988)), ...]

[ ('Pia', 'Schwarz', (11,11,2003)), ('Andreas', 'Beyer', (16,3,1988)), ..., ]

('Pia', 'Schwarz', (11,11,2003))

L

e

juenger vergleich

Die Black-Box-Modellierungen zeigen Situationen, in denen eine Vergleichsoperation an die Funktion übergeben wird. In der oberen Abbildung wird als Vergleichsoperation der Vergleich der Nachnamen übergeben, in der unteren Abbildung ein Vergleich der Geburtsdaten.

Page 44: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

44

Ein Parameter für Vergleichsfunktionen

einfuegen

[('Andreas', 'Beyer', (16,3,1988)), ...]

[('Andreas', 'Beyer', ...), ..., ('Pia', 'Schwarz', ...), ...]

('Pia', 'Schwarz', (11,11,2003))

L

e

kleinerNachname vergleich

Funktionale Programmierung ermöglicht solche Situationen, in denen einer Funktion Daten übergeben werden können, die selbst eine Funktion darstellen.

def einfuegen(e, L, vergleich): if len(L) == 0: return [e] else: if vergleich(e, L[0]) == True: return [e] + L else: return [L[0]] + einfuegen(e, L[1:], vergleich)

def sortieren(L, vergleich): if len(L) == 0: return [] else: return einfuegen(L[0], sortieren(L[1:], vergleich), vergleich)

Page 45: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

45 Funktionsaufrufedef einfuegen(e, L, vergleich): if len(L) == 0: return [e] else: if vergleich(e, L[0]) == True: return [e] + L else: return [L[0]] + einfuegen(e, L[1:], vergleich)

def sortieren(L, vergleich): if len(L) == 0: return [] else: return einfuegen(L[0], sortieren(L[1:], vergleich), vergleich)

# Test

personendaten = [ ('Jennifer', 'Abel', (15,12,1993)), ('Philipp', 'Bach', (21,4,1997)), ('Andreas', 'Beyer', (16,3,1988)), ('Alexander', 'Heinrich', (17,3,1999)), ('Tobias', 'Klein', (1,3,1997)), ('Britta', 'Koch', (23,5,1995)), ('Maximilian', 'Meyer', (21,6,1986)), ('Adriana', 'Müller', (21,1,2001)), ('Silke', 'Schmidt', (13,7,1990)), ('Oliver', 'Schmitt', (14,4,1994)), ('Simone', 'Schuster', (20,12,2000)), ('Pia', 'Schwarz', (11,11,2003)), ('Paul', 'Schwarz', (11,11,2003))]

# Situation 1

def kleinerAlphabetischNachname(person1, person2): if person1[1] < person2[1]: return True else: return False

print(sortieren(personendaten, kleinerAlphabetischNachname))

Aufgabe:

Teste selbst die verallgemeinerte Sortierfunktion.

Page 46: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

46 Aufgabe# Test

personendaten = [...]

# Situation 2

def geburtsdatum(person): …

def tag(datum): …

def monat(datum): …

def jahr(datum): return …

def kleinerDatum(datum1, datum2): …

def juenger(person1, person2): …

print(sortieren(personendaten, juenger))

Aufgabe:

Die Personendaten sollen nach dem Alter der Personen – von jung nach alt – sortiert werden. Entwickle passende Funktionen. Du kannst dich an dem Vorschlag orientieren.

Page 47: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

47 Funktionen höherer Ordnung

Eine Funktion höherer Ordnung ist eine Funktion, die Funktionen als Übergabedaten erhält oder eine Funktion als Rückgabedatum zurückliefert.

def rechnen(f, a, b): return f(a, b)

def add(a, b): return a + b

def sub(a, b): return a - b

>>> rechnen(add, 3, 6)9>>> rechnen(sub, 5, 2)3

Page 48: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

48 Aufgaben

Aufgabe:

(a) Kann man die Funktion rechnen auch zur Ausführung von Vergleichsoperationen benutzen? Führe hierzu geeignete Tests durch.

(b) Die Funktion anwenden ist folgendermaßen definiert. Teste die Funktion anwenden mit verschiedenen konkreten Funktionen.

def anwenden(f, a): return f(a)

Page 49: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

49

Funktion auf Listenelemente anwenden

Im Sportverein steht die Berechnung des jährlichen Mitgliedsbeitrags an. Zwei Beitragberechnungsmodelle sollen durchgespielt werden. Im ersten Modell ist der Beitrag nur grob gestaffelt: Kinder, Jugendliche und Erwachsene zahlen jeweils einen festen Betrag. Im zweiten Modell ist der Beitrag direkt an das Alter (am Ende des Kalenderjahres) gekoppelt.

# Berechnungsmodell 1

def beitraegeBerechnen1(personenListe): if personenListe == []: return [] else: (vorname, name, geburtsdatum) = personenListe[0] aktuellesJahr = 2010 alter = aktuellesJahr - geburtsdatum[2] if alter < 10: beitrag = 20 elif alter < 20: beitrag = 40 else: beitrag = 60 personNeu = (vorname, name, geburtsdatum, beitrag) return [personNeu] + beitraegeBerechnen2(personenListe[1:])

# Anwendung

personendaten = [('Jennifer', 'Abel', (15,12,1993)), ...]

print(beitraegeBerechnen1(personendaten))

Page 50: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

50

Funktion auf Listenelemente anwenden

Aufgabe

(a) Teste erst einmal die beiden Funktionen. Entwickle selbst ein weiteres Berechnungsmodell und die passende Berechnungsfunktion.

(b) Vergleiche die Funktionsdefinitionen. Welche Gemeinsamkeiten fallen auf?

(c) Siehst du eine Möglichkeit, eine Funktion höherer Ordnung zu benutzen, um die gemeinsame Berechnungsstruktur zu erfassen?

# Berechnungsmodell 2

def beitraegeBerechnen2(personenListe): if personenListe == []: return [] else: (vorname, name, geburtsdatum) = personenListe[0] aktuellesJahr = 2010 alter = aktuellesJahr - geburtsdatum[2] beitrag = 3 * alter personNeu = (vorname, name, geburtsdatum, beitrag) return [personNeu] + beitraegeBerechnen1(personenListe[1:])

# Anwendung

personendaten = [('Jennifer', 'Abel', (15,12,1993)), ...]

print(beitraegeBerechnen2(personendaten))

Page 51: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

51 Der map-Operator

Verarbeitungssituation: Jedes Element einer Liste wird mit der gleichen Vorschrift verarbeitet und durch das verarbeitete Element ersetzt.

Wir benutzen den sogenannen map-Operator zur Erfassung dieser Verarbeitungssituation.

Beispiele zur Anwendung des map-Operators:

Page 52: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

52 Der map-Operator

def myMap(liste, f): if liste == []: return [] else: return [f(liste[0])] + myMap(liste[1:], f)

personendaten = [('Jennifer', 'Abel', (15,12,1993)),...]

def beitragBerechnen1(person): (vorname, name, geburtsdatum) = person aktuellesJahr = 2010 alter = aktuellesJahr - geburtsdatum[2] if alter < 10: beitrag = 20 elif alter < 20: beitrag = 40 else: beitrag = 60 personNeu = (vorname, name, geburtsdatum, beitrag) return personNeu

print(myMap(personendaten, beitragBerechnen1))

def myMap(liste, f): return [f(x) for x in liste]

Page 53: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

53 Aufgaben

Aufgabe:

Benutze den map-Operator, um für eine Funktion eine Wertetabelle zu erstellen.

Page 54: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

54 Listenelemente herausfiltern

Die Liste der Datensätze zur Verwaltung der Mitglieder des Sportvereins soll nach verschiedenen Kriterien durchsucht werden: Wer gilt als erwachsen (d.h. ist am Ende des Jahres mindestens 18 Jahre alt)? Wer hat im Februar Geburtstag? Wer hat einen Nachnamen, der mit S beginnt? Es sollen alle Datensätze, die das jeweilige Suchkriterium erfüllen, ermittelt werden.

def erwachsenHerausfiltern(liste): if liste == []: return [] else: person = liste[0] geburtsdatum = person[2] aktuellesJahr = 2010 alter = aktuellesJahr - geburtsdatum[2] if alter >= 18: return [liste[0]] + erwachsenHerausfiltern(liste[1:]) else: return erwachsenHerausfiltern(liste[1:])

# Test

personendaten = [('Jennifer', 'Abel', (15,12,1993)), ...]

# Anfrage 1print(erwachsenHerausfiltern(personendaten))

Page 55: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

55 Listenelemente herausfiltern

Aufgabe

(a) Entwickle entsprechende Funktionsdefinitionen, um die Datensätze zu den beiden anderen oben genannten Kriterien herauszufiltern.

(b) Beschreibe das Schema, das all diesen Filteroperationen zu Grunde liegt.

(c) Siehst du eine Möglichkeit, eine Funktion höherer Ordnung zu benutzen, um das gemeinsame Berechnungsschema zu erfassen?

def erwachsenHerausfiltern(liste): if liste == []: return [] else: person = liste[0] geburtsdatum = person[2] aktuellesJahr = 2010 alter = aktuellesJahr - geburtsdatum[2] if alter >= 18: return [liste[0]] + erwachsenHerausfiltern(liste[1:]) else: return erwachsenHerausfiltern(liste[1:])

# Test

personendaten = [('Jennifer', 'Abel', (15,12,1993)), ...]

# Anfrage 1print(erwachsenHerausfiltern(personendaten))

Page 56: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

56 Der filter-Operator

Verarbeitungssituation: Elemente einer Liste, die eine bestimmte Bedingung erfüllen, werden in einer neuen Liste zusammengestellt.

Wir benutzen den sogenannen filter-Operator zur Erfassung dieser Verarbeitungssituation.

Beispiele zur Anwendung des filter-Operators:

Page 57: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

57 Der filter-Operator

def myFilter(liste, f): if liste == []: return [] else: if f(liste[0]): return [liste[0]] + myFilter(liste[1:], f) else: return myFilter(liste[1:], f)

personendaten = [('Jennifer', 'Abel', (15,12,1993)),...]

def erwachsen(person): geburtsdatum = person[2] aktuellesJahr = 2010 alter = aktuellesJahr - geburtsdatum[2] if alter >= 18: return True else: return False

# Anfrage 1print(myFilter(personendaten, erwachsen))

def myFilter(liste, f): return [x for x in liste if f(x)]

Page 58: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

58 Aufgaben

Aufgabe:

Benutze den filter-Operator, um alle positiven / negativen Zahlen aus einer Zahlenliste herauszufiltern.

Aufgabe:

Benutze den filter-Operator, um Quicksort geschickt zu implementieren.

Page 59: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

59 Teil 4

Deklarative Programmierung

Page 60: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

60 Dialog über DatenverarbeitungI: Hallo! Ich vertrete hier die imperative Programmierung.

F: Hallo, und ich vertrete die funktionale Programmierung.

I: Neulich hast du behauptet, dass man Programme ohne Variablen und Zuweisungen schreiben kann und dass man keine Schleifen benötigt.

F: Das stimmt - zumindest so ungefähr!

I: Ich kann mir das immer noch nicht so recht vorstellen. Wie soll das z.B. bei einem ganz einfachen Algorithmus wie dem folgenden funktionieren?

F: Umdenken ist die Devise! Der Algorithmus benutzt Befehle, um die Daten zu verarbeiten. Die Daten werden dabei mit Hilfe von Variablen verwaltet. Ich mache das ganz anders. Ich konzipiere eine Funktion, die das Gewünschte leistet, und definiere sie mit Hilfe von Regeln.

I: Sehe ich das richtig, dass da auch Variablen vorkommen?

F: Ja, aber nur als Parameter, um Daten an die Funktion zu übergeben. Der entscheidende Unterschied ist, dass sie ihre Werte nicht verändern.

I: Das ist ja alles schön und gut. Aber, wozu soll das Ganze gut sein? Ich komme mit meiner Methode doch auch zum Ziel.

F: Stimmt, wir kommen beide zum Ziel, aber mit ganz unterschiedlichen Methoden. Du benutzt Algorithmen, die letztlich aus Anweisungen bzw. Befehlen bestehen. Diese Befehle richten sich an eine tatsächliche oder gedachte Maschine. Bei der Entwicklung von Algorithmen musst du also denken wie eine Maschine.

I: Das habe ich zwar noch nie so empfunden, aber eigentlich hast du recht. Und wie denkst du?

ALGORITHMUS Summenberechnung:{vorher: n aus N}setze s auf 0setze i auf 0SOLANGE i <= n: erhöhe s um i erhöhe i um 1{nachher: s = 0+1+2+...+n}

FUNKTION summe:{Fall 1:}n == 0: summe(n)->0{Fall 2:}n > 0: summe(n)->n+summe(n-1)

Page 61: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

61 Dialog über DatenverarbeitungF: Ich entwickle Beschreibungen anstatt Befehle zu erteilen. Ich beschreibe das gewünschte Berechnungsverhalten mit einer Funktion, die den Ausgangsdaten die Zieldaten zuordnet. Anschließend lege ich mit Hilfe von Regeln die Zuordnung präzise fest.

I: Das erinnert mich irgendwie an Funktionsdefinitionen in der Mathematik.

F: Ja, da macht man das ganz genauso.

I: Und warum sollen wir beim Programmieren vorgehen wie Mathematiker? Hat das irgendwelche Vorteile?

F: Beim Programmieren macht man leicht Fehler. Gib zu, dass du auch schon mal die Anweisung "erhöhe i um 1" vergessen hast. Wenn man funktional programmiert, kann man sich leichter von der Korrektheit der Programme überzeugen. Ich mache mir die Korrektheit von Regeln immer anhand typischer Beispiele klar:

I: Ok, das sehe ich ein! Aber, wenn ich mich so umschaue, stelle ich fest, dass fast alle imperativ programmieren wie ich. So richtig durchgesetzt hast du dich noch nicht, oder?

F: Viele kennen mich halt nicht - das ist irgendwie schade. Die, die mich kennen, benutzen meinen deklarativen Ansatz beim Entwickeln von Prototypen. Es geht hier darum, schnell ein System zu entwickeln, das korrekt arbeitet bzw. das gewünschte Verhalten zeigt. Es kommt nicht darauf an, das Laufzeitverhalten zu optimieren oder Benutzerfreundlichkeit zu gewährleisten.

I: Kannst du das an einem Beispiel klarmachen?

F: Gerne, aber erst im nächsten Abschnitt.

FUNKTION summe:{Fall 1:}n == 0: summe(n)->0{Fall 2:}n > 0: summe(n)->n+summe(n-1)

Page 62: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

62 Beschreiben statt Befehlen

Imperative Programmierung besteht darin, eine (mehr oder weniger abstrakte) Maschine mit Hilfe von Anweisungen zu steuern.

Dabei wird beschrieben, wie die Ergebnisse berechnet werden sollen. Zentrale Bausteine imperativer Programme sind Wertzuweisungen, die i.a. den momentanen Variablenzustand (Speicherzustand) verändern. Imperative Programmierung ist wegen der Möglichkeit, Seiteneffekte zu produzieren, recht fehleranfällig.

Deklarative Programmierung besteht darin, den Problemkontext (die Miniwelt) mit gegebenen Mitteln zu beschreiben. Funktionale Programmierung - als eine Form der deklarativen Programmierung - benutzt hierzu Funktionen.

Bei der deklarativen Programmierung wird somit beschrieben, was in der Modellwelt gelten soll.Die funktionale Programmierung arbeitet dabei ohne Speichervariablen. Variablen kommen hier nur als Funktionsvariablen zur Übergabe von Funktionsargumenten vor. Seiteneffekte sind demnach in der funktionalen Programmierung nicht möglich. Das Verhalten einer Funktion wird vollständig durch die Funktionsdeklarationen festgelegt.

Funktionale Programmierung erfolgt auf einem höheren Abstraktionsniveau. Es ergeben sich dadurch Programme, die kürzer, leichter zu durchschauen und weniger fehleranfälliger sind.

Funktionale Programmierung eignet sich zum „Prototyping“.

Page 63: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

63 Prototyping

Bei der Entwicklung neuer Produkte wird zunächst oft ein Prototyp erstellt. Dabei handelt es sich um ein funktionsfähiges Modell, das dem geplanten Produkt in vielen Bereichen entspricht, meist aber auch eine Reihe von Vereinfachungen aufweist.

Prototypen werden - insbesondere bei komplexen technischen Systemen - zunächst einmal erstellt, um Erfahrungen mit dem neuen System und seiner Entwicklung zu sammeln.

Prototypen kommen entsprechend auch bei der Entwicklung komplexer Software zum Einsatz. Wir skizzieren im Folgenden, wie ein Prototyp zu einem RSA-Kryptosystem mit Hilfe der funktionalen Programmierung erstellt werden kann.

Page 64: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

64 Prototyp zu einem Kryptosystem

Beim RSA-Verfahren werden natürliche Zahlen mit Hilfe eines (öffentlichen bzw. privaten) Schlüssels in neue Zahlen umwandelt.

from kryptosystem_rsa import *# Testprogrammn = 116063e = 4097d = 51137oeffentlicherSchluessel = (e, n)privaterSchluessel = (d, n)s0 = 'Köln'print(s0)s1 = verschluesseln(s0, oeffentlicherSchluessel, codierenZeichenketteZahlenliste)print(s1)s2 = entschluesseln(s1, privaterSchluessel, decodierenZahlenlisteZeichenkette)print(s2)

>>> Köln[99070, 100824, 50230]Köln

Die Funktionen zur Realisierung des Prototyps findet man auf den Seiten von www.inf-schule.de (1.22.4.2).

Page 65: Funktionale Programmierung Klaus Becker 2014. 2 Funktionale Programmierung

65 Literaturhinweise

[Becker 99] K. Becker: Funktionale Programmierung. Materialien zum Lehrplan Informatik. LMZ 1999. (http://informatikag.bildung-rp.de/html/funktprog.html)

[Becker 00] K. Becker: Problemlösen mit dem Computeralgebrasystem Derive - informatisch betrachtet. (http://informatikag.bildung-rp.de/html/derive.html)

[Becker 04] K. Becker: Funktionale Programmierung mit Caml. (http://informatik.bildung-rp.de/fileadmin/user_upload/informatik.bildung-rp.de/Weiterbildung/pps/WB-FunktionaleProgrammierungCaml.pps)

[Lorenz 12] G. Funktionale Modellierung und Rekursion. Oldenbourg Verlag 2012.