Powerpoint-Präsentation

Download Report

Transcript Powerpoint-Präsentation

Slide 1

Funktionale Programmierung
Klaus Becker
2007


Slide 2

2

Programmieren mit Funktionen

Mit Funktionen kann man programmieren. Die
Programme bestehen aus Funktionsdeklarationen.
Funktionsdeklarationen werden mit Hilfe von
Funktionskomposition, Fallunterscheidungen und
Rekursion aufgebaut. ...

Zielsetzung: Einblick in die funktionale Programmierung gewinnen

Grundideen verstehen
 Grundkonzepte kennen lernen

Relevanz anhand von Miniprojekten erkennen


Slide 3

3

Teil 1

Von der Registermaschine
zur funktionalen Abstraktion


Slide 4

Registermaschine

4

Eine Registermaschine bearbeitet beliebig eingebbare Daten nach einem
fest vorgegebenen Programm.
Daten

1:
2:
3:
4:
5:

5
3
0
0
0

..

> 1
2
3
4
5
6

JMP
INC
DEC
TST
JMP
HLT

4
1
2
2
2

Programm

> 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 i

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

> x HLT

Beende die Bearbeitung.


Slide 5

Aufgabe

5

Was leistet das unten abgebildete Registermaschinenprogramm?
Messen Sie die Zeit, die Sie brauchen, um das herauszufinden.
1 TST 2
2 JMP 4
3 JMP 7
4 TST 3
5 JMP 13
6 JMP 10
7 TST 3
8 JMP 19
9 HLT
10 TST 2
11 JMP 17
12 HLT
13 DEC 2
14 DEC 3
15 INC 1
16 JMP 1
17 DEC 2
18 JMP 10
19 DEC 3
20 JMP 7


Slide 6

6

Aufgabe

Was leistet das unten abgebildete (Python-) Programm?
Messen Sie die Zeit, die Sie brauchen, um das herauszufinden.
while (R2 <> 0) and (R3 <> 0):
R1 = R1 + 1
R2 = R2 - 1
R3 = R3 - 1
while R2 <> 0:
R2 = R2 - 1
while R3 <> 0:
R3 = R3 -1


Slide 7

7

Spaghetti-Code mit Sprunganweisungen
Durch die vielen Sprunganweisungen verliert man leicht
den Überblick über die Ablauflogik.
1 TST 2
2 JMP 4
3 JMP 7
4 TST 3
5 JMP 13
6 JMP 10
7 TST 3
8 JMP 19
9 HLT
10 TST 2
11 JMP 17
12 HLT
13 DEC 2
14 DEC 3
15 INC 1
16 JMP 1
17 DEC 2
18 JMP 10
19 DEC 3
20 JMP 7

Wer strukturiert programmiert, verzichtet auf solche
Sprunganweisungen, auch wenn die
Programmiersprache sie zur Verfügung stellt.
Viele Programmiersprachen stellen keine
Sprunganweisungen zur Verfügung. Dann können solch
schwer zu durchschauenden Programme gar nicht erst
geschrieben werden.

"Spaghetti-Code"


Slide 8

8

Ablaufkontrolle mit Kontrollanweisungen

An Stelle von Sprunganweisungen benutzt man Kontrollstrukturen, um die
Ablauflogik strukturiert zu beschreiben.
1 TST 2
2 JMP 4
3 JMP 7
4 TST 3
5 JMP 13
6 JMP 10
7 TST 3
8 JMP 19
9 HLT
10 TST 2
11 JMP 17
12 HLT
13 DEC 2
14 DEC 3
15 INC 1
16 JMP 1
17 DEC 2
18 JMP 10
19 DEC 3
20 JMP 7

while (R2 <> 0) and (R3 <> 0):
R1 = R1 + 1
R2 = R2 - 1
R3 = R3 - 1
while R2 <> 0:
R2 = R2 - 1
while R3 <> 0:
R3 = R3 -1

Ablaufbeschreibung mit Kontrollstrukturen

Ablaufbeschreibung mit Sprunganweisungen


Slide 9

9

Aufgabe

Vergleichen Sie die beiden Programme. Welche Version ist besser?

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, 7)
>>> m
5

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

>>> minimum(5, 7)
5


Slide 10

Seiteneffekte

10

Das Unterprogramm auf der linken Seite verändert den Wert einer globalen
Variablen. Das Unterprogramm hat einen sog. Seiteneffekt.
def minimum(a, b):
global m
while (a <> 0) and (b <> 0):
m = m + 1
a = a - 1
b = b - 1

>>>
>>>
>>>
8
>>>
>>>
>>>
5

m = 3
minimum(5, 7)
m
m = 0
minimum(5, 7)
m

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

>>> minimum(5, 7)
5


Slide 11

11

Programme ohne Seiteneffekte

Eine Funktion soll normalerweise aus den Argumenten einen Wert
berechnen und nichts anderes nebenbei tun. Von diesem Prinzip weichen
Programmierer jedoch immer wieder ab, etwa indem sie in der Funktion
globale Variablen verändern. Wer strukturiert programmiert, verzichtet auf
Seiteneffekte.
Es gibt Programmiersprachen, die keine Seiteneffekte zulassen. Die Idee
dabei ist, auf Wertzuweisungen zu verzichten, so dass keine
unbeabsichtigten Seiteneffekte möglich sind.
def minimum(a, b):
if a == 0:
return a
else:
if b == 0:
return b
else:
return 1 + minimum(a-1, b-1)
Unterprogramm ohne Wertzuweisung


Slide 12

12

Zielsetzung

Ziel ist es, die Grundideen funktionaler Programmierung anhand von
Beispielen problemorientiert zu erarbeiten. Insbesondere soll dabei
herausgearbeitet werden, dass Programmierung ohne Wertzuweisungen
möglich ist.


Slide 13

13

Teil 2

Konzepte der funktionalen Programmierung


Slide 14

Fallstudie: Chiffrieren

14

Ziel ist es, Chiffrierverfahren (die auf modularem Rechnen basieren), mit
Hilfe funktionaler Programme zu beschreiben.
PYLZFOWBNQCYBUVNCBLGYC
HYAYBYCGMWBLCZNYHNTCZY
LN
VDOYH
FDHVDU

A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
D E F G H I J K L M N O P Q R S T U V W X Y Z A B C
Quelltext:
SALVECAESAR

Schlüssel: D

Geheimtext:
VDOYHFDHVDU


Slide 15

15

Additives Chiffrierverfahren

Codierung:
Code: A → 1
Blocklänge: 2
Verschlüsselung:
öffentlicher Schlüssel
(d, m) = (2102, 3000)
Entschlüsselung:
privater Schlüssel
(e, m) = (898, 3000)
Decodierung:
Code: A → 1
Blocklänge: 2

AA → 0101
AB → 0102
...
ZZ → 2626

0119#2005#1809#24

z → (z + d) % m

0119#2005#1809#24

Bed.: z < m
m > maxCode
z → (z + e) % m
Bed.:
(d + e) % m = 0
AA → 0101
AB → 0102
...
ZZ → 2626

AS#TE#RI#X

2221#1107#1010#2126
2221#1107#1010#2126
0119#2005#1809#24
0119#2005#1809#24

AS#TE#RI#X


Slide 16

16

Additives Chiffrierverfahren

Wir betrachten zunächst das Verschlüsseln und Entschlüsseln von
Zahlenfolgen mit Schlüsseln, die aus zwei Komponenten bestehen. Da Verund Entschlüsseln gleich funktionieren, reicht es, nur das Verschlüsseln zu
betrachten.
Verschlüsselung:
öffentlicher Schlüssel
(d, m) = (2102, 3000)
Entschlüsselung:
privater Schlüssel
(e, m) = (898, 3000)

z → (z + d) % m

0119#2005#1809#24

Bed.: m ist größer als
die maximale Codezahl

2221#1107#1010#2126

z → (z + e) % m

2221#1107#1010#2126

Bed.:
d+e=m

0119#2005#1809#24


Slide 17

Funktionale Modellierung

17

Verschlüsselung:
öffentlicher Schlüssel
(d, m) = (2102, 3000)

z → (z + d) % m
Bed.: z < m
m > maxCode

0119#2005#1809#24
2221#1107#1010#2126

Spezifikation:
verschluesselnZahl
119
(2102, 3000)

zahl
schluessel

2221

Eingaben:
zahl: die zu verschlüsselnde Zahl
schluessel: Zahlenpaar bestehend aus der zu addierenden Konstante und dem Divisionsmodul
Ausgabe:
die berechnete verschlüsselte Zahl


Slide 18

Funktionale Modellierung

18

Verschlüsselung:
öffentlicher Schlüssel
(d, m) = (2102, 3000)

z → (z + d) % m
Bed.: z < m
m > maxCode

0119#2005#1809#24
2221#1107#1010#2126

Spezifikation:
verschluesseln
[119, 2005, 1809, 24]
(2102, 3000)

zahlenListe
schluessel

[2221, 1107, 1010, 2126]

Eingaben:
zahlenListe: Liste mit den zu verschlüsselnden Zahlen
schluessel: Zahlenpaar bestehend aus der zu addierenden Konstante und dem Divisionsmodul
Ausgabe:
Liste mit den berechneten verschlüsselten Zahlen


Slide 19

Funktionales Programm

19

Verschlüsselung:
öffentlicher Schlüssel
(d, m) = (2102, 3000)

z → (z + d) % m
Bed.: z < m
m > maxCode

0119#2005#1809#24
2221#1107#1010#2126

Spezifikation:
verschluesselnZahl
119
(2102, 3000)

zahl
schluessel

2221

Implementierung:
def verschluesselnZahl(zahl, schluessel):
return (zahl + schluessel[0]) % schluessel[1]


Slide 20

Funktionales Programm

20

Verschlüsselung:
öffentlicher Schlüssel
(d, m) = (2102, 3000)

z → (z + d) % m
Bed.: z < m
m > maxCode

0119#2005#1809#24
2221#1107#1010#2126

Spezifikation:
verschluesseln
[119, 2005, 1809, 24]
(2102, 3000)

zahlenListe
schluessel

[2221, 1107, 1010, 2126]

Implementierung:
def verschluesseln(zahlenListe, schluessel):
if len(zahlenListe) == 0:
return []
else:
return [verschluesselnZahl(zahlenListe[0], schluessel)] +
verschluesseln(zahlenListe[1:], schluessel)


Slide 21

Datenstruktur "Tupel"

21

Tupel sind unveränderbare Sequenzen. Man verwendet Tupel, wenn man
ein Objekt repräsentieren möchte, das aus mehreren Komponenten
besteht.
Spezifikation:
Tupel

verschluesselnZahl
119

(2102, 3000)

zahl
schluessel

2221

Implementierung:
def verschluesselnZahl(zahl, schluessel):
return (zahl + schluessel[0]) % schluessel[1]
Zugriff auf die Komponenten


Slide 22

Datenstruktur "Liste"

22

Listen sind veränderbare Sequenzen. Sie können (in Python) Objekte
beliebigen Typs enthalten. Mit Listen kann man komplexere Strukturen
modellieren.
Spezifikation:
Liste

verschluesseln

[119, 2005, 1809, 24]
(2102, 3000)

Implementierung:

zahlenListe
schluessel

Liste
[2221, 1107, 1010, 2126]

Listenoperationen

def verschluesseln(zahlenListe, schluessel):
if len(zahlenListe) == 0:
return []
else:
return [verschluesselnZahl(zahlenListe[0], schluessel)] +
verschluesseln(zahlenListe[1:], schluessel)


Slide 23

23

Listenoperationen

Das Python-Protokoll zeigt die Listenoperationen, die im Folgenden benötigt
werden. Weitere Listenoperationen findet man in der Dokumentation.
>>> zahlenListe = []
>>> zahlenListe
[]
>>> len(zahlenListe)
0
>>> zahlenListe = [119, 2005, 1809, 24]
>>> zahlenListe
[119, 2005, 1809, 24]
>>> zahlenListe[0]
119
>>> zahlenListe[1:]
[2005, 1809, 24]
>>> [zahlenListe[0]] + zahlenListe[1:]
[119, 2005, 1809, 24]
>>>
...

leere Liste

Länge einer Liste

Zugriff auf Listenelemente
Zugriff auf eine Restliste

Konkatenation von Listen


Slide 24

24

Aufgabe

Testen Sie die im funktionalen Programm vorkommenden
Listenoperationen. Variieren Sie dabei auch die vorkommenden
Parameterwerte.
>>> zahlenListe = []
>>> zahlenListe
[]
>>> len(zahlenListe)
0
>>> zahlenListe = [119, 2005, 1809, 24]
>>> zahlenListe
[119, 2005, 1809, 24]
>>> zahlenListe[0]
119
>>> zahlenListe[1:]
[2005, 1809, 24]
>>> [zahlenListe[0]] + zahlenListe[1:]
[119, 2005, 1809, 24]
>>>
...


Slide 25

Rekursive Problemreduktion

25

Rekursive Problemreduktion: Reduziere des Problems auf ein
entsprechendes, aber „verkleinertes“ Problem.
Fall 1: Bearbeite eine leere Liste
verschluesseln([], (2102, 3000))

→ []

Rekursionsanfang:
Löse das Problem direkt

[]

Fall 2: Bearbeite eine nicht-leere Liste
verschluesseln([119, 2005, 1809, 24], (2102, 3000))
[2221, 1107, 1010, 2126]
→ [verschluesselnZahl(119, (2102, 3000))] +
[2221]
verschluesseln([2005, 1809, 24], (2102, 3000))
[1107, 1010, 2126]

Rekursionsschritt:
Löse ein entsprechendes
Problem


Slide 26

26

Aufgabe

Fügen Sie Ausgabeanweisungen ein und verfolgen Sie so die Auswertung
der einzelnen Funktionsaufrufe.
def verschluesseln(zahlenListe, schluessel):
print zahlenListe, schluessel
if len(zahlenListe) == 0:
return []
else:
return [verschluesselnZahl(zahlenListe[0], schluessel)] +
verschluesseln(zahlenListe[1:], schluessel)


Slide 27

27

Kontrollstruktur "Rekursion"

Rekursion wird in der funktionalen Programmierung als Kontrollstruktur
benutzt, um wiederkehrende Berechnungen durchzuführen.
def verschluesseln(zahlenListe, schluessel):
if len(zahlenListe) == 0:
return []
else:
return [verschluesselnZahl(zahlenListe[0], schluessel)] +
verschluesseln(zahlenListe[1:], schluessel)
verschluesseln([119, 2005, 1809, 24], (2102, 3000))
→ [verschluesselnZahl(119, (2102, 3000))] +
verschluesseln([2005, 1809, 24], (2102, 3000))
→ [2221] +
verschluesseln([2005, 1809, 24], (2102, 3000))
→ [2221] +
[verschluesselnZahl(2005, (2102, 3000))] +
verschluesseln([1809, 24], (2102, 3000))
→ [2221] +
[1107] +
verschluesseln([1809, 24], (2102, 3000))
...


Slide 28

28

Kontrollstruktur "Rekursion"

→ [2221] +
[1107] +
[verschluesselnZahl(1809, (2102, 3000))] +
verschluesseln([24], (2102, 3000))
→ [2221] +
[1107] +
[1010] +
verschluesseln([24], (2102, 3000))
→ [2221] +
[1107] +
[1010] +
[verschluesselnZahl(24, (2102, 3000))] +
verschluesseln([], (2102, 3000))
→ [2221] +
[1107] +
[1010] +
[2126] +
verschluesseln([], (2102, 3000))
→ [2221] +
[1107] +
[1010] +
[2126] +
[]
→ [2221, 1107, 1010, 2126]


Slide 29

Kontrollstrukturen

29

Funktionsdeklarationen werden in der funktionalen Programmierung mit
Hilfe von
- Funktionskomposition,
- Fallunterscheidungen und
- Rekursion
aufgebaut. Diese Strukturen legen letztlich die Ablaufkontrolle fest.
def verschluesseln(zahlenListe, schluessel):
if len(zahlenListe) == 0:
return []
else:
return [verschluesselnZahl(zahlenListe[0], schluessel)] +
verschluesseln(zahlenListe[1:], schluessel)

Fallunterscheidung

Rekursion

Funktionskomposition


Slide 30

Aufgabe

30

Zur Übung rekursiver Funktionsdeklarationen sollen folgende Funktionen
implementiert werden. Gehen Sie analog zur Funktion "verschluesseln" vor.

Spezifikation:
addieren
[6, 13, 0, 5]
7

zahlenListe
konstante

[13, 20, 7, 12]

Spezifikation:
nullErsetzen
[6, 0, 13, 0, 0, 5, 3]
7

zahlenListe
konstante

[6, 7, 13, 7, 7, 5, 3]


Slide 31

31

Aufgabe

In der Datei "ChiffriersystemModularesAddierenRekursiv.py" finden Sie eine
Implementierung des Chiffriersystems basierend auf modularer Addition,
die (außer zum Testen) keine Wertzuweisungen benutzt. Analysieren Sie die
Funktionsdeklarationen auch im Hinblick auf die vorkommenden
Kontrollstrukturen.
Verschlüsselung:

öffentlicher Schlüssel
(d, m) = (2102, 3000)
Entschlüsselung:
privater Schlüssel
(e, m) = (898, 3000)

z → (z + d) % m
Bed.: z < m
m > maxCode
z → (z + e) % m
Bed.:
(d + e) % m = 0

0119#2005#1809#24
2221#1107#1010#2126
2221#1107#1010#2126
0119#2005#1809#24


Slide 32

32

Aufgabe

Ändern Sie die entsprechenden Funktionsdeklarationen so ab, dass man das
multiplikative Chiffrierverfahren erhält.

Verschlüsselung:

öffentlicher Schlüssel
(d, m) = (7, 30)
Entschlüsselung:
privater Schlüssel
(e, m) = (13, 30)

z → (z * d) % m
Bed.:
zz → (z * e) % m
Bed.:
(d * e) % m = 1

01#19#20#05#18#09#24
07#13#20#05#06#03#18
07#13#20#05#06#03#18
01#19#20#05#18#09#24


Slide 33

33

Codeduplizierung

Die Implementierungen zur Verschlüsselung mit modularer Addition und
modularer Multiplikation weisen auffallende Ähnlichkeiten auf.
def verschluesselnZahlAdd(zahl, schluessel):
return (zahl + schluessel[0]) % schluessel[1]
def verschluesselnAdd(zahlenListe, schluessel):
if len(zahlenListe) == 0:
return []
else:
return [verschluesselnZahlAdd(zahlenListe[0], schluessel)] +
verschluesselnAdd(zahlenListe[1:], schluessel)
def verschluesselnZahlMul(zahl, schluessel):
return (zahl * schluessel[0]) % schluessel[1]
def verschluesselnMul(zahlenListe, schluessel):
if len(zahlenListe) == 0:
return []
else:
return [verschluesselnZahlMul(zahlenListe[0], schluessel)] +
verschluesselnMul(zahlenListe[1:], schluessel)


Slide 34

Funktionen als Eingabeobjekte

34

Codeduplizierung lässt sich vermeiden, wenn man Funktionen als
Eingabeobjekte von Funktionen zulässt.

Spezifikation:
Funktion

verschluesseln

z → (z + d) % m

[119, 2005, 1809, 24]
(2102, 3000)
Liste

Tupel

verfahren
zahlenListe
schluessel

[2221, 1107, 1010, 2126]


Slide 35

35

Funktionen als Eingabeobjekte

Die Implementierung zeigt, dass man Funktionen hier wie andere Objekte
auch als Parameter übergeben kann.
def verschluesselnZahlAddieren(zahl, schluessel):
return (zahl + schluessel[0]) % schluessel[1]
def verschluesselnZahlMultiplizieren(zahl, schluessel):
return (zahl * schluessel[0]) % schluessel[1]
def verschluesselnZahl(verfahren, zahl, schluessel):
return verfahren(zahl, schluessel)
def verschluesseln(verfahren, zahlenListe, schluessel):
if len(zahlenListe) == 0:
return []
else:
return [verschluesselnZahl(verfahren, zahlenListe[0], schluessel)] +
verschluesseln(verfahren, zahlenListe[1:], schluessel)
def verschluesselnModularesAddieren(zahlenListe, schluessel):
return verschluesseln(verschluesselnZahlAddieren, zahlenListe, schluessel)
def verschluesselnModularesMultiplizieren(zahlenListe, schluessel):
return verschluesseln(verschluesselnZahlMultip.., zahlenListe, schluessel)


Slide 36

36

Aufgabe

Testen Sie die Implementierung in der Datei
"ChiffriersystemModularesRechnenRekursiv.py".
Erweitern Sie diese Implementierung um die Möglichkeit, Verschlüsselung
auch mit modularem Potenzieren durchzuführen.


Slide 37

37

Funktionale Programmierung

Mit Funktionen kann man programmieren. Die
Programme bestehen aus Funktionsdeklarationen.
Ein Programmaufruf erfolgt mit einem
funktionalen Berechnungsausdruck.

Funktionsdeklaration

def verschluesseln(zahlenListe, schluessel):
if len(zahlenListe) == 0:
return []
else:
return [verschluesselnZahl(zahlenListe[0], schluessel)] +
verschluesseln(zahlenListe[1:], schluessel)
verschluesseln([119, 2005, 1809, 24], (2102, 3000))

Berechnungsausdruck


Slide 38

38

Funktionale Programmierung
Funktionsdeklarationen werden mit Hilfe von
- Funktionskomposition,
- Fallunterscheidungen und
- Rekursion
aufgebaut.

Funktionskomposition
def verschluesselnZahl(zahl, schluessel):
return (zahl + schluessel[0]) % schluessel[1]
def verschluesseln(zahlenListe, schluessel):
if len(zahlenListe) == 0:
return []
Rekursion
else:
return [verschluesselnZahl(zahlenListe[0], schluessel)] +
verschluesseln(zahlenListe[1:], schluessel)
Fallunterscheidung


Slide 39

39

Funktionale Programmierung
Objekte können mit Hilfe von Tupelbildung und
Listen zu neuen Einheiten zusammengefasst
werden.
Funktionen können als Eingabeobjekte für weitere
Funktionen benutzt werden.

Funktion

Tupel

def verschluesselnZahl(verfahren, zahl, schluessel):
return verfahren(zahl, schluessel)
def verschluesseln(verfahren, zahlenListe, schluessel):
if len(zahlenListe) == 0:
Liste
return []
else:
return [verschluesselnZahl(verfahren, zahlenListe[0], schluessel)] +
verschluesseln(verfahren, zahlenListe[1:], schluessel)


Slide 40

40

Miniprojekte

Funktionale Programmierung eignet sich sehr gut, um schnell ein System zu
entwickeln und zu testen. Man konzentriert sich nur auf die "Logik" des
Systems, nicht auf "schmückendes Beiwerk". Die Programme sollen dabei
kurz und gut überschaubar sein.

Im Folgenden soll diese Vorgehensweise anhand von drei Miniprojekten
aufgezeigt werden.


Slide 41

41

Miniprojekt "Geometrische Abbildungen"

Ziel ist es, ein System zu entwickeln, mit dem man einfache geometrische
Operationen durchführen kann.


Slide 42

42

Miniprojekt "Automatensimulator"

Ziel ist es, ein System zu entwickeln, mit dem man das Verhalten eines
beliebigen Automaten simulieren kann.
0

0

akzeptor

1

g

u
Ok!

1

00011011


Slide 43

43

Miniprojekt "Programminterpreter"

Ziel ist es, ein System zur Ausführung einfacher imperativer Programme zu
entwickeln.
{b: 2; u: 5}
BEGIN
p := 1;
WHILE u > 0 DO
BEGIN
IF u mod 2 = 1 THEN
BEGIN
u := u – 1;
p := p * b;
END;
u := u div 2;
b := b* b;
END
END
{b: 256; u: 0; p: 32}

Interpreter


Slide 44

44

Aufgabe

Wählen Sie eines der Miniprojekte aus und realisieren Sie das skizzierte
System. Sie können versuchen, das System völlig selbständig zu entwickeln,
oder die im Folgenden angebotenen Hilfen zu nutzen.


Slide 45

45

Teil 3

Miniprojekt: Geometrische Abbildungen


Slide 46

46

Geometrische Abbildungen

Ziel ist es, ein System zu entwickeln, mit dem man einfache geometrische
Operationen durchführen kann.


Slide 47

47

Schritt 1: Verschiebungen

Verschiebungen können mit Hilfe von Vektoren dargestellt werden. Die
Abbildung von Punkten lässt sich dann durch Addition von Vektoren
realisieren.

Vieleck:
A(0, 0), B(40, 0), C(40, 30), D(0, 30)
Verschiebung mit Vektor:

v=

10
10

verschobenes Vieleck:
A'(10, 10), B'(50, 10), C'(50, 40), D'(10, 40)


Slide 48

48

Listenrepräsentation

Wir repräsentieren Vektoren mit Hilfe von Listen. Ebenso stellen wir Punkte
und Punktfolgen mit Hilfe von Listen dar.

Vieleck:
[[0, 0], [40, 0], [40, 30], [0, 30]]
Verschiebung mit Vektor [10, 10]:

[0, 0] + [10, 10] [10, 10]
[40, 0] + [10, 10] [50, 10]
[40, 30] + [10, 10] [50, 40]
[0, 30] + [10, 10] [10, 40]
verschobenes Vieleck:
[[10, 10], [50, 10], [50, 40], [10, 40]]


Slide 49

Aufgabe

49

Entwickeln Sie ein funktionales Programm für die Addition von Vektoren.
Um das Programm flexibel benutzen zu können, sollen Vektoren beliebig
viele Komponenten haben können.

Spezifikation:
add
[60, 30, 40]

v

[10, 0, 30]

w

[70, 30, 70]


Slide 50

Aufgabe

50

Realisieren Sie jetzt die Abbildung "Verschieben" mit Hilfe der bereits
implementierten Vektoraddition.
Spezifikation:
verschiebenPunkt

[40, 30]

punkt

[10, 10]

vektor

[50, 30]

Spezifikation:
verschieben
[[20, 10], [40, 30], [70, 0]]

vieleck

[10, 10]

vektor

[[30, 20], [50, 40], [80, 10]]


Slide 51

Lösungsvorschlag

51

Spezifikation:
add
[60, 30, 40]

v

[10, 0, 30]

w

[70, 30, 70]

Implementierung:
def add(v, w):
if len(v) == 0:
if len(w) == 0:
return []
else:
return w
else:
if len(w) == 0:
return v
else:
return [v[0] + w[0]] + add(v[1:], w[1:])


Slide 52

Lösungsvorschlag

52

Spezifikation:

verschiebenPunkt
[40, 30]

punkt

[10, 10]

vektor

Spezifikation:

[50, 30]

verschieben

[[20, 10], [40, 30], [70, 0]]

vieleck

[10, 10]

vektor

[[30, 20], [50, 40], [80, 10]]

def verschiebenPunkt(punkt, vektor):
return add(punkt, vektor)

def verschieben(vieleck, vektor):
if len(vieleck) == 0:
return []
else:
return [verschiebenPunkt(vieleck[0], vektor)] +
verschieben(vieleck[1:], vektor)


Slide 53

53

Test mit Turtlegrafik

Testen Sie die einzelnen
Funktionsdeklarationen mit Hilfe
geeigneter Testfälle.
Zur visuellen Kontrolle können Sie die
geometrischen Objekte auch mit Hilfe
von Turtlegrafik darstellen. Kopieren
Sie zu diesem Zweck die Daten
"xturtle.py" (von G. Lingl aus dem
Buch "Python für Kids") in die
Standardbibliothek von Python.
Benutzen Sie die Hilfsfunktion zum
Zeichnen von Vielecken (siehe
"GeometrischeOperationen1.py").
Beachten Sie, dass diese Hilfsfunktion
Seiteneffekte in Form von Grafiken
erzeugt und damit nicht mehr rein
funktional ist.


Slide 54

54

Test mit Turtlegrafik

def zeichneVieleck(punkte):
# wird nur zum Zeichnen benutzt
if len(punkte) > 0:
penup()
setpos(punkte[0])
pendown()
streckenzug = punkte[1:] + [punkte[0]]
for punkt in streckenzug:
goto(punkt)

if __name__ == "__main__":
# Test der einzelnen Funktionen
import doctest
doctest.testmod(verbose=True)
# Visueller Test mit Turtlegrafik
from xturtle import *
reset()
vieleck1 = [[0, 0], [40, 0], [40, 30], [0, 30]]
vieleck2 = verschieben(vieleck1, [10, 10])
zeichneVieleck(vieleck1)
zeichneVieleck(vieleck2)


Slide 55

55

Schritt 2: Streckungen

Streckungen lassen sich durch
Multiplikation eines Vektors mit
einer Zahl realisieren.

Fall1: Streckzentrum im Ursprung
Streckung mit dem Faktor k:
multipliziere die Koordinaten der Punkte mit
dem Streckfaktor k
Fall 2: Streckzentrum beliebig
Verschiebe erst das Streckzentrum in den
Ursprung, führe die Steckung aus und
verschiebe wieder zurück an den
Ausgangspunkt
Beispiel:
Vieleck:
A(30, 0), B(70, 0), C(70, 30), D(30, 30)
Streckung mit dem Streckzentrum (0, 0) und
dem Streckfaktor 2:
gestrecktes Vieleck:
A'(60, 0), B'(140, 0), C'(140, 60), D'(60, 60)


Slide 56

56

Listenrepräsentation

Wir benötigen hier die Multiplikation eines Vektors mit einer Zahl.

Vieleck:
[[20, 0], [60, 0], [60, 30], [20, 30]]
Streckung mit dem Streckzentrum [0, 0] und
dem Streckfaktor 2:
2*[20, 0] [40, 0]
...
gestrecktes Vieleck:

[[40, 0], [120, 0], [120, 60], [40, 60]]


Slide 57

57

Aufgabe

Entwickeln Sie geeignete Funktionen zur Durchführung von Streckungen.


Slide 58

58

Lösungsvorschlag

def mul(k, v):
if len(v) == 0:
return []
else:
return [k * v[0]] + mul(k, v[1:])

def streckenPunktUrsprung(punkt, faktor):
return mul(faktor, punkt)
def streckenUrsprung(vieleck, faktor):
if len(vieleck) == 0:
return []
else:
return [streckenPunktUrsprung(vieleck[0], faktor)] +
streckenUrsprung(vieleck[1:], faktor)
def strecken(vieleck, zentrum, faktor):
return verschieben(
streckenUrsprung(
verschieben(vieleck, mul(-1, zentrum)),
faktor),
zentrum)


Slide 59

59

Schritt 3: Drehungen

Drehungen lassen sich durch
Multiplikation einer Matrix mit
einem Vektor realisieren.

Fall1: Drehzentrum im Ursprung
Drehung des Punktes P(x, y) um den
Winkel w:
cos(w) -sin(w)

x
*

sin(w)

cos(w)

x'


y

y'

Es gilt:

x' = cos(w)*x + (- sin(w))*y
y' = sin(w)*x + cos(w)*y
Fall 2: Drehzentrum beliebig
Verschiebe erst das Drehzentrum in den
Ursprung, führe die Drehung aus und
verschiebe wieder zurück an den
Ausgangspunkt


Slide 60

60

Listenrepräsentation

Wir repräsentieren Matrizen hier ebenfalls mit Hilfe von Listen.:

Vieleck:
[[20, 0], [60, 0], [60, 30], [20, 30]]
Matrix für eine Linksdrehung um das
Drehzentrum [0, 0] und dem Drehwinkel
90°: [[0, -1], [1, 0]]
[[0, -1], [1, 0]] * [20, 0]  [0, 20]
...
gedrehtes Vieleck:
[[0, 20], [0, 60], [-30, 60], [-30, 20]]


Slide 61

61

Aufgabe

Entwickeln Sie geeignete Funktionen zur Durchführung von Drehungen. Bei
der Implementierung mit Python müssen Sie durch "import math" die
benötigten mathematischen Operationen bereitstellen. Ein Aufruf der cosFunktion lautet hier "math.cos(x)". Das Ergebnis wird im Bogenmaß
geliefert. Mit "math.radians(w)" können Sie einen Winkel im Gradmaß ins
Bogenmaß umrechen. Die umgekehrte Operation führt "math.degrees(x)"
aus. Weitere Informationen erhalten Sie in der mitgelieferten
Dokumentation.


Slide 62

62

Lösungsvorschlag

def skalprod(v, w):
if len(v) == 0:
return 0
else:
return (v[0] * w[0]) + skalprod(v[1:], w[1:])

def matrixmul(m, v):
if len(m) == 0:
return []
else:
return [skalprod(m[0], v)] + matrixmul(m[1:], v)


Slide 63

63

Lösungsvorschlag

def drehenPunktUrsprung(punkt, w):
import math
return matrixmul([
[math.cos(math.radians(w)), -math.sin(math.radians(w))],
[math.sin(math.radians(w)), math.cos(math.radians(w))]], punkt)

def drehenUrsprung(vieleck, w):
if len(vieleck) == 0:
return []
else:
return [drehenPunktUrsprung(vieleck[0], w)] +
drehenUrsprung(vieleck[1:], w)

def drehen(vieleck, zentrum, winkel):
return verschieben(
drehenUrsprung(
verschieben(vieleck, mul(-1, zentrum)),
winkel),
zentrum)


Slide 64

64

Weitere Ideen

Erweitern Sie das System um die Möglichkeit, Spiegelungen durchzuführen.


Slide 65

65

Teil 4

Miniprojekt: Automatensimulator


Slide 66

66

Miniprojekt "Automatensimulator"

Ziel ist es, ein System zu entwickeln, mit dem man das Verhalten eines
beliebigen Automaten simulieren kann.
0

0

akzeptor

1

g

u
Ok!

1

00011011


Slide 67

Schritt 1: Automatenbeschreibung

67

Mit Hilfe endlicher Automaten kann man formale Sprachen erkennen. Der
dargestellte endliche Automat erkennt die Sprache der 0-1-Wörter mit
gerader Parität (gerader Anzahl von 1en). Es handelt sich um einen sog.
Akzeptor, der keine Ausgaben erzeugt.
0

0

1

g

u
1

Zustandsmenge:

Z = {g, u}

Eingabemenge:

E = {0, 1}

Anfangszustand:

za = g

Endzustände:

zE = {g}

Überführungsfunktion:

:
:
:
:

(g,
(g,
(u,
(u,

0)
1)
0)
1)






g
u
u
g


Slide 68

Aufgabe

68

Der Automat lässt sich wie folgt mit
Funktionen modellieren. Implementieren Sie diese Funktionen.

0

0

1

Spezifikation:
g

anfangszustandP

'g'

Spezifikation:
endzustandP
'g'

z

True

Spezifikation:
deltaP
'g'

z

'0'

e

'g'

u
1

Zustandsmenge:

Z = {g, u}

Eingabemenge:

E = {0, 1}

Anfangszustand:

za = g

Endzustände:

zE = {g}

Überführungsfunktion:

:
:
:
:

(g,
(g,
(u,
(u,

0)
1)
0)
1)






g
u
u
g


Slide 69

69

Aufgabe

Modellieren und implementieren Sie
noch einen weiteren Automaten
(ohne Ausgabe).


Slide 70

70

Aufgabe

Der unten abgebildete Automat zur Steuerung einer Ampel ist ein
Transduktor. In jedem Zustand wird bei jeder Eingabe eine Ausgabe
erzeugt. Z. B. wird im Zustand "rot" bei der Eingabe "t" (Tag) die Ausgabe
"OOo" (rot an, gelb an, grün aus) erzeugt. Beschreiben Sie diesen
Transduktor mit Hilfe von Funktionen.


Slide 71

71

Lösungsvorschlag

def anfangszustandP():
return 'g'

Zustandsmenge:

Z = {g, u}

Eingabemenge:

E = {0, 1}

def endzustandP(z):
if (z == 'g'):
return True
elif (z == 'u'):
return False

Anfangszustand:

za = g

Endzustände:

zE = {g}

def deltaP(z, e):
if (z == 'g') and (e == '0'):
return 'g'
elif (z == 'u') and (e == '0'):
return 'u'
elif (z == 'g') and (e == '1'):
return 'u'
elif (z == 'u') and (e == '1'):
return 'g'

Überführungsfunk.: :
:
:
:
0

(g,
(g,
(u,
(u,

0)
1)
0)
1)






g
u
u
g
0

1

g

u
1


Slide 72

72

Lösungsvorschlag

def anfangszustandA():
return 'ge';;
def deltaA(z, e):
if (z == 'ro') and (e == 't'):
return 'rg'
elif (z == 'rg') and (e == 't'):
return 'gr'
elif (z == 'gr') and (e == 't'):
return 'ge'
elif (z == 'ge') and (e == 't'):
return 'ro'
...
def lambdaA(z, e):
if (z == 'ro') and (e == 't'):
return 'OOo'
elif (z == 'rg') and (e == 't'):
return 'ooO'
elif (z == 'gr') and (e == 't'):
return 'oOo'
...


Slide 73

73

Schritt 2: Verarbeitung v. Eingabefolgen

Es soll ein Akzeptor-System entwickelt werden, mit dem eine Folge von
Eingaben verarbeiten werden kann und rückgemeldet wird, ob diese Folge
in einen Endzustand überführt.

0

0

1

Ok!

00011011
g

u
1


Slide 74

74

Aufgabe

Erweitern Sie das funktionale Programm
um die spezifizierten Funktionen.
Tipp: siehe nächste Folie
def anfangszustandP():
return 'g'
def endzustandP(z):
if (z == 'g'):
return True
elif (z == 'u'):
return False

def deltaP(z, e):
if (z == 'g') and (e == '0'):
return 'g'
elif (z == 'u') and (e == '0'):
return 'u'
elif (z == 'g') and (e == '1'):
return 'u'
elif (z == 'u') and (e == '1'):
return 'g'

0

0

1

g

u
1

Spezifikation:
simulatorP
'g'
['0', '1', '0']

z
eListe

'u'

Spezifikation:
akzeptorP

['0', '1', '0']

eListe

Fal
se


Slide 75

Aufgabe

75

Tipp:
Verallgemeinern Sie die unten an
konkreten Beispielen gezeigten
Problemreduktionen.

0

0

1

g

u
1

Fall 1: Verarbeite eine leere Eingabenliste
simulartorP('g', [])  'g'
Fall 2: Verarbeite eine nicht-leere Eingabenliste

simulatorP('g', ['1', '0', '0'])  simulatorP('u', ['0', '0'])]
u

'u'


Slide 76

Aufgabe

76

Entwickeln Sie eine Funktion zur Realisierung eines Ampelsimulators.

Spezifikation:
simulatorA
'ro'
['t', 't', 't', 't']

z
eListe

[OOo, ooO, oOo, Ooo]


Slide 77

Lösungsvorschlag

77

Fall 1: Verarbeite eine leere Eingabenliste

simulartorP('g', [])  'g'
Fall 2: Verarbeite eine nicht-leere Eingabenliste
simulatorP('g', ['1', '0', '0'])  simulatorP('u', ['0', '0'])]
u

'u'

def simulatorP(z, eListe):
if len(eListe) == 0:
return z
else:
return simulatorP(deltaP(z, eListe[0]), eListe[1:])
def akzeptorP(eListe):
return enzustand(simulatorP(anfangszustand(), eListe))


Slide 78

78

Weitere Ideen

Entwickeln Sie ein System, bei dem die Arbeitsweise eines Transduktors
(Automat mit Ausgabe) simuliert wird.


Slide 79

79

Schritt 3: Automat als Eingabe

Es soll ein universelles Akzeptor-System entwickelt werden, mit dem eine
Folge von Eingaben mit einem beliebig vorgegebenen Automaten
verarbeiten werden kann.

def anfangszustandP():
...
def endzustandP(z):
...
def deltaP(z, e):
...

Ok!

00011011


Slide 80

Aufgabe

80

Verallgemeinern Sie das bisher entwickelte Simulator-System. Benutzen Sie
die folgende Vereinbarung:
Eine Automatenbeschreibung ist ein Tripel (az, ez, de) mit:
- az ist eine Funktion zur Beschreibung des Anfangszustands.
- ez ist eine Funktion zur Beschreibung der Endzustände.
- de ist eine Überführungsfunktion, die jedem Zustand und jeder Eingabe
aus einen neuen Zustand zuordnet.
Spezifikation:
Funktionen

simulator

(anfangszustandP, enzustandP, deltaP)
'g'
['0', '1', '0']

aut
z
eListe

'u'


Slide 81

81

Lösungsvorschlag

def simulator(aut, z, eListe):
if len(eListe) == 0:
return z
else:
return simulator(aut, aut[2](z, eListe[0]), eListe[1:])
def akzeptor(aut, eListe):
return aut[1](simulator(aut, aut[0](), eListe))


Slide 82

82

Weitere Ideen

Entwickeln Sie ein System, bei dem die Arbeitsweise eines beliebigen
Transduktors simuliert wird.


Slide 83

83

Teil 5

Miniprojekt: Programminterpreter


Slide 84

84

Miniprojekt "Programminterpreter"

Ziel ist es, ein System zur Ausführung einfacher imperativer Programme zu
entwickeln.
{b: 2; u: 5}
BEGIN
p := 1;
WHILE u > 0 DO
BEGIN
IF u mod 2 = 1 THEN
BEGIN
u := u – 1;
p := p * b;
END;
u := u div 2;
b := b* b;
END
END
{b: 256; u: 0; p: 32}

Interpreter


Slide 85

Problemvereinfachung

85

Ausgangszustand
Zuweisungsprogramm
Endzustand

{x: 2; y: 5}
BEGIN
z := x;
x := y;
y := z
END

Interpreter

{x: 5; y: 2; z: 5}

Wir betrachten zunächst nur Programme, die aus "primitiven Zuweisungen"
vom Typ := bestehen.


Slide 86

Funktionale Modellierung

86

Ausgangszustand
Zuweisungsprogramm
Endzustand

{x: 2; y: 5}
BEGIN
z := x;
x := y;
y := z
END

Interpreter

{x: 5; y: 2; z: 5}

Spezifikation:
PrimZuwSeqAusfuehren
[(':=', 'z', 'x'), (':=', 'x', 'y'), (':=', 'y', 'z')]
[('x', 2), ('y', 5)]

zuweisungen
zustand

[('x', 5), ('y', 2), ('z', 5)]


Slide 87

87

Schritt 1: Variablenzustände

Variablenzustände beschreiben die jeweils aktuellen Variablenbelegungen.
Zur Verarbeitung einer primitiven Zuweisung wie z := x muss der Wert
einer Variablen (hier x) bzgl. des aktuellen Variablenzustands ermittelt
werden und der Wert einer Variablen (hier y) im Variablenzustand verändert
(oder neu angelegt) werden.

{x: 2; y: 5}
z := x;
{x: 2; y: 5; z: 2}
x := y;

{x: 5; y: 5; z: 2}
y := z
{x: 5; y: 2; z: 2}


Slide 88

88

Aufgabe

Modellieren Sie geeignete Funktionen, mit denen der Wert einer Variablen
bzgl. eines Variablenzustands ermittelt werden kann und der Wert einer
Variablen im Variablenzustand verändert (oder neu angelegt) werden kann.
Entwickeln Sie anschließend mit Hilfe rekursiver
Problemreduktionsschemata geeignete Funktionsdeklarationen.


Slide 89

Lösungsvorschlag

89

Spezifikation:
VariablenWert
'y'
[('x', 2), ('y', 5)]

bezeichner

zustand

5

Spezifikation:
NeuerZustand

'z'
2
[('x', 2), ('y', 5)]

bezeichner
wert
zustand

[('x', 2), ('y', 5), ('z', 2)]

NeuerZustand
'x'
5
[('x', 2), ('y', 5), ('z', 2)]

bezeichner

wert
zustand

[('x', 5), ('y', 5), ('z', 2)]


Slide 90

90

Lösungsvorschlag

def VariablenWert(bezeichner, zustand):
if len(zustand) == 0:
return '?'
else:
if bezeichner == zustand[0][0]:
return zustand[0][1]
else:
return VariablenWert(bezeichner, zustand[1:])
def NeuerZustand(bezeichner, wert, zustand):
if len(zustand) == 0:
return [(bezeichner, wert)]
else:
if bezeichner == zustand[0][0]:
return [(bezeichner, wert)] + zustand[1:]
else:
return [zustand[0]] +
NeuerZustand(bezeichner, wert, zustand[1:])


Slide 91

91

Schritt 2: Zuweisungsinterpreter

Mit Hilfe geeigneter Funktionen sollen jetzt einzelne primitive Zuweisungen
bzw. Sequenzen primitiver Zuweisungen ausgeführt werden.

{x: 2; y: 5}
z := x;
{x: 2; y: 5; z: 2}
x := y;

{x: 5; y: 5; z: 2}
y := z
{x: 5; y: 2; z: 2}


Slide 92

92

Aufgabe

Modellieren und implementieren Sie die hierzu erforderlichen Funktionen.


Slide 93

93

Lösungsvorschlag

Spezifikation:
PrimZuwAusfuehren
(':=', 'z', 'y')
[('x', 2), ('y', 5)]

zuweisung
zustand

[('x', 2), ('y', 5), ('z', 2)]

Spezifikation:
PrimZuwSeqAusfuehren
[(':=', 'z', 'x'), (':=', 'x', 'y'), (':=', 'y', 'z')]
[('x', 2), ('y', 5)]

zuweisungen
zustand

[('x', 5), ('y', 2), ('z', 5)]


Slide 94

94

Lösungsvorschlag

def PrimZuwAusfuehren(zuweisung, zustand):
return NeuerZustand(zuweisung[1],
VariablenWert(zuweisung[2], zustand), zustand)
def PrimZuwSeqAusfuehren(zuweisungen, zustand):
if len(zuweisungen) == 0:
return zustand
else:
return PrimZuwSeqAusfuehren(zuweisungen[1:],
PrimZuwAusfuehren(zuweisungen[0], zustand))


Slide 95

95

Schritt 3: Terminterpreter

Auf der rechten Seite einer Zuweisung sollen jetzt auch beliebige
Rechenterme erlaubt sein. Wir beschränken uns auf das Rechnen mit
ganzen Zahlen. Als Rechenoperationen sollen daher +, -, *, / (Division ohne
Rest), % (Rest bei der Division) betrachtet werden.

{x: 2; y: 5}
x := x-y;
{x: -3; y: 5}
y := x+y;
{x: -3; y: 2}
x := y-x

{x: 5; y: 2}


Slide 96

96

Aufgabe

Ergänzen Sie die bereits begonnene Funktionsdeklaration und
verallgemeinern Sie den Zuweisungsinterpreter. Beachten Sie die hier
gewählte Darstellung von Termen, z. B.:
z+(x-y) wird dargestellt durch ('+', 'z', ('-', 'x', 'y'))
x+1 wird dargestellt durch ('+', 'x', 1)
def TermWert(term, zustand):
if isinstance(term, int):
return term
else:
if not isinstance(term, tuple):
return VariablenWert(term, zustand)
else:
if term[0] == '+':
return TermWert(term[1], zustand) +
TermWert(term[2], zustand)
else:
...


Slide 97

97

Schritt 4: Bedingungsinterpreter

Als nächstes sollen Anweisungen mit Bedingungen (wie z. B. if (x > 0) then
...) betrachtet werden. Hierzu muss der Interpreter Bedingungen auswerten
können. Der Einfachheit halber betrachten wir nur Bedingungen vom Typ
. Logische Verknüpfungen von Bedingungen
sollen also keine Rolle spielen.
Spezifikation:
BooleWert
('>', 'y', ('+', 'x', 'x'))
[('x', 2), ('y', 5)]

term
zustand

True


Slide 98

98

Aufgabe

Entwickeln Sie analog zur Auswertung von Rechentermen eine Funktion zur
Auswertung von Bedingungen.


Slide 99

99

Schritt 5: Kontrollinterpreter

Ziel ist es, Fallunterscheidungs- und Wiederholungsanweisungen
auszuführen, wie sie etwa im unten dargestellten Programm vorkommen.

BEGIN
p := 1;
WHILE u > 0 DO
BEGIN
IF u mod 2 = 1 THEN
BEGIN
u := u – 1;
p := p * b;
END;
u := u div 2;
b := b* b;
END
END


Slide 100

100

Aufgabe

Überlegen Sie sich eine Darstellung von Kontrollanweisungen (wie im
Programm) mit den von Python zur Verfügung gestellten Datenstrukturen.
Entwickeln Sie geeignete Funktionen zur Ausführung dieser Anweisungen.

BEGIN
p := 1;
WHILE u > 0 DO
BEGIN
IF u mod 2 = 1 THEN
BEGIN
u := u – 1;
p := p * b;
END;
u := u div 2;
b := b* b;
END
END


Slide 101

101

Lösungsvorschlag

Fallunterscheidung:
('if', (..Bedingung..), [..Then-Anweisungen..], [..Else-Anweisungen..])
Wiederholung:
('while', (..Bedingung..), [..Anweisungen..])
BEGIN
p := 1;
WHILE u > 0 DO
BEGIN
IF u mod 2 = 1 THEN
BEGIN
u := u – 1;
p := p * b;
END;
u := u div 2;
b := b* b;
END
END

[
(':=', 'p', 1),
('while', ('>', 'u', 0),
[
('if', ('==', ('%', 'u', 2), 1),
[
(':=', 'u', ('-', 'u', 1)),
(':=', 'p', ('*', 'p', 'b'))
],[]),
(':=', 'u', ('/', 'u', 2)),
(':=', 'b', ('*', 'b', 'b'))
])
]


Slide 102

102

Lösungsvorschlag

def AnwAusfuehren(anweisung, zustand):
if anweisung[0] == ':=':
return NeuerZustand(anweisung[1],
TermWert(anweisung[2], zustand), zustand)
else:
if anweisung[0] == 'if':
if BooleWert(anweisung[1], zustand):
return AnwSeqAusfuehren(anweisung[2], zustand)
else:
return AnwSeqAusfuehren(anweisung[3], zustand)
else:
if anweisung[0] == 'while':
if BooleWert(anweisung[1], zustand):
return AnwAusfuehren(anweisung,
AnwSeqAusfuehren(anweisung[2], zustand))
else:
return zustand


Slide 103

103

Lösungsvorschlag

def AnwSeqAusfuehren(anweisungen, zustand):
if len(anweisungen) == 0:
return zustand
else:
return AnwSeqAusfuehren(anweisungen[1:],
AnwAusfuehren(anweisungen[0], zustand))


Slide 104

104

Lösungsvorschlag

def ProgrammAusfuehren(programm, zustand):
return AnwSeqAusfuehren(programm, zustand)

Beachten Sie, dass ein Programm hier immer eine Anweisungssequenz ist,
auch wenn es nur aus einer Anweisung besteht.


Slide 105

105

Teil 6

Deklarative Programmierung


Slide 106

106

Ein Problem - zwei Lösungen

Problem:
Wie fügt man die Elemente einer Listen (die alle Zeichenketten sein sollen)
zu einer einzigen Zeichenkette zusammen?
Lösung:

Lösung:

Stell eine Hilfsliste "ergebnis" wie folgt
zusammen:
Starte mit der einer leeren Liste.
Füge Schritt für Schritt alle Elemente der
Liste jeweils am Ende der Hilfsliste ein.
Die am Schluss erhaltene Hilfsliste ist die
gesuchte Liste.

Wenn die Liste leer ist, dann ist die leere
Liste bereits das Ergebnis. Wenn die Liste
nicht leer ist, dann erhält man das Ergebnis
wie folgt: Man fügt das erste Element
vorne an die Zeichenkette, die man erhält,
wenn man alle Elemente der Restliste
zusammenfügt.

def zusammenfuegen(liste):
ergebnis = ''
for wort in liste:
ergebnis = ergebnis + wort
return ergebnis

def zusammenfuegen(liste):
if len(liste) == 0:
return ''
else:
return liste[0] + zusammenfuegen(liste[1:])

Imperativer Ansatz:
Man beschreibt Schritt für Schritt den
Vorgang, wie man alle Elemente der Liste
zusammenfügt.

Deklarativer Ansatz:
Man beschreibt, welche Eigenschaften das
Ergebnis haben soll, das man beim
Zusammenfügen erhält.


Slide 107

107

Imperative Programmierung

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

A.-Zustand

{liste: ['HA', 'LL', 'O']}

Anweisungen

def zusammenfuegen(liste):
ergebnis = ''
for wort in liste:
ergebnis = ergebnis + wort
return ergebnis

E.-Zustand

{ergebnis: 'HALLO']}

Registermaschine

Ansatz: Beschreiben, 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.


Slide 108

108

Deklarative Programmierung

Deklarative Programmierung besteht darin, den Problemkontext
(Miniwelt) mit gegebenen Mitteln (hier: Funktionen) zu beschreiben.

Term

zusammenfuegen(['HA', 'LL', 'O'])

def zusammenfuegen(liste):
if len(liste) == 0:
Deklarationen
return ''
else:
return liste[0] + zusammenfuegen(liste[1:])

Ergebnis

Reduktionsmaschine

'HALLO'

Ansatz: Beschreiben, was in der Modellwelt gelten soll
Die funktionale Programmierung arbeitet 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.


Slide 109

109

Fazit

Funktionale Programmierung erfolgt auf einem höheren Abstraktionsniveau:
- keine Anweisungen an eine Maschine,
- sondern Beschreibung funktionaler Zusammenhänge.
Konsequenzen:
- Funktionale Programme sind kurz.
- Funktionale Programme sind leicht zu verstehen.
- Funktionale Programmierung ist wenig fehleranfällig.
- Funktionale Programmierung eignet sich zum „Prototyping“.


Slide 110

110

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.bildungrp.de/fileadmin/user_upload/informatik.bildung-rp.de/Weiterbildung/pps/WBFunktionaleProgrammierungCaml.pps)
[Fischbacher 97] T. Fischbacher: Funktionale Programmierung. In: LOG IN 17 (1997) Heft 3 /
4, S. 24-26.

[ISB 97] Staatliches Institut für Schulpädagogik und Bildungsforschung München (Hrsg.):
Funktionales Programmieren in Gofer. Baustein zur Didaktik der Informatik. München, 1997.
[Puhlmann 98] H. Puhlmann: Funktionales Programmieren - Eine organische Verbindung von
Informatikunterricht und Mathematik. In: LOG IN 18 (1998) Heft 2, S. 46-50.
[Schwill 93] A. Schwill: Funktionale Programmierung mit Caml. In: LOG IN 13 (1993) Heft 4,
S. 20-30.
[Wagenknecht 94] Christian Wagenknecht: Rekursion. Ein didaktischer Zugang mit
Funktionen. Bonn: Dümmlers Verlag 1994.
[Wolff von Gudenberg 96] J. Wolff. von Gudenberg: Algorithmen, Datenstrukturen, Funktionale
Programmierung. Eine praktische Einführung mit Caml Light. Bonn: Addison-Wesley 1996.