Powerpoint-Präsentation

Werbung
Funktionale Programmierung
mit Caml
Klaus Becker
2004
Programmieren mit Funktionen
2
Funktionale Programmierung
0
KB
0
akzeptor
1
g
u
Ok!
1
00011011
Funktionale Programmierung
3
KB
Teil 1
Funktionen als Programme
4
Die Welt der Automaten
Funktionale Programmierung
0
KB
0
1
g
u
1
Mit Hilfe endlicher Automaten kann man formale Sprachen
erkennen. Der dargestellte endliche Automat erkennt die Sprache
der 0-1-Worte mit gerader Parität (gerader Anzahl von 1en).
5
Eine Automatenbeschreibung
Funktionale Programmierung
0
KB
0
1
g
u
1
Zustandsmenge:
Z = {g, u}
Anfangszustand:
za = g
Endzustände:
zE = {g}
Eingabemenge:
E = {0, 1}
Überführungsfunktion: : (g, 0)  g
: (u, 0)  u
: (g, 1)  u
: (u, 1)  g
Funktionale Modellierung
Funktionale Programmierung
6
KB
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)




type zustandP = g | u;;
type eingabeP = e0 | e1;;
let anfangszustandP = g;;
let endzustandP = function
g -> true | u -> false;;
let deltaP = function
(g, e0) -> g | (g, e1) -> u |
(u, e0) -> u | (u, e1) -> g ;;
g
u
u
g
Funktionale Modellierung
7
Funktionale Programmierung
anfangszustandP
KB
endzustandP: g  true
g u
g u
zustand
zustand
true false
bool
type zustandP = g | u;;
type eingabeP = e0 | e1;;
let anfangszustandP = g;;
let endzustandP = function
g -> true | u -> false;;
let deltaP = function
(g, e0) -> g | (g, e1) -> u |
(u, e0) -> u | (u, e1) -> g ;;
deltaP: (g, e1)  u
g u
zustand
e0
e1
eingabe
8
Modellierungskonzept
type zustandP = g | u;;
Funktionale Programmierung
type eingabeP = e0 | e1;;
KB
let anfangszustandP = g;;
let endzustandP = function
g -> true | u -> false;;
Typdeklaration
Konstantendeklaration
Funktionsdeklaration
let deltaP = function
(g, e0) -> g | (g, e1) -> u |
(u, e0) -> u | (u, e1) -> g ;;
Objektbereiche werden mit Hilfe von Typen beschrieben.
Eigenschaften von Objekten und Zusammenhänge zwischen
Objekten mit Hilfe von Funktionen (und Konstanten).
9
Auswertung von Deklarationen
#Type zustandP defined.
Funktionale Programmierung
#Type eingabeP defined.
KB
#anfangszustandP : zustandP = g
#endzustandP : zustandP -> bool = <fun>
#deltaP : zustandP * eingabeP -> zustandP = <fun>
Auswertung durch Caml
type zustandP = g | u;;
type eingabeP = e0 | e1;;
let anfangszustandP = g;;
let endzustandP = function
g -> true | u -> false;;
let deltaP = function
(g, e0) -> g | (g, e1) -> u |
(u, e0) -> u | (u, e1) -> g ;;
Benutzereingabe
Signaturanalyse
10
Signatur der Funktion
Funktionale Programmierung
Auswertung:
KB
#deltaP : zustandP * eingabeP -> zustandP = <fun>
Die Funktion deltaP ordnet einem Paar bestehend aus einem
Objekt vom Typ zustandP und einem Objekt vom Typ eingabeP ein
Objekt vom Typ zustandP zu.
Benutzereingabe:
type zustandP = g | u;;
type eingabeP = e0 | e1;;
...
let deltaP = function
(g, e0) -> g | (g, e1) -> u |
(u, e0) -> u | (u, e1) -> g ;;
Funktionsdeklaration
Funktionsanwendung
11
Auswertung:
Funktionale Programmierung
...
#deltaP : zustandP * eingabeP -> zustandP = <fun>
#deltaP(u, e0);;
- : zustandP = u
Die Auswertung des funktionalen Ausdrucks delta(e0, g) liefert das
Objekt u vom Typ zustand.
Aktuelle Benutzereingabe:
Vorherige Benutzereingaben:
deltaP(u, e0);;
type zustandP = g | u;;
type eingabeP = e0 | e1;;
...
let deltaP = function
(g, e0) -> g | (g, e1) -> u |
(u, e0) -> u | (u, e1) -> g ;;
KB
Funktionsanwendung
12
Auswertung:
Funktionale Programmierung
#endzustandP(deltaP(deltaP(anfangszustandP, e1), e1));;
KB
- : bool = true
Benutzereingabe:
endzustandP(deltaP(deltaP(anfangszustandP, e1), e1));;
Die Auswertung des funktionalen Ausdrucks
deltaP(deltaP(anfangszustandP, e1), e1)
liefert das Objekt u vom Typ zustandP.
Funktionale Programme
Funktionale Programmierung
13
Ein funktionales Programm besteht aus einer Menge von
Funktionsdeklarationen (und evtl. benötigten Typdeklarationen)
und einem funktionalen Ausdruck (Berechnungsausdruck).
Funktionaler Ausdruck
Funktionsdeklarationen
Benutzereingabe:
Benutzereingabe:
deltaP(u, e0);;
type zustandP = g | u;;
type eingabeP = e0 | e1;;
...
let deltaP = function
(g, e0) -> g | (g, e1) -> u |
(u, e0) -> u | (u, e1) -> g ;;
KB
14
Programmierkonzept
Funktionale Programmierung
type zustandP = g | u;;
KB
type eingabeP = e0 | e1;;
...
let deltaP = function
(g, e0) -> g | (g, e1) -> u |
(u, e0) -> u | (u, e1) -> g ;;
deltaP(u, e0);;
Mit Funktionen kann man programmieren.
Die Programme bestehen aus
Funktionsdeklarationen und einem
funktionalen Berechnungsausdruck.
Übung
Funktionale Programmierung
15
Entwickeln Sie ein funktionales Programm zur Simulation einer
Ampelschaltung mit Tag-Nacht-Betrieb. Testen Sie das Programm.
KB
Lösungsvorschlag
16
type zustandA = ro | rg | ge | gr | aa;;
Funktionale Programmierung
type eingabeA = t | n;;
KB
type ausgabeA = Ooo | OOo | ooO | oOo | ooo;;
let anfangszustandA = ge;;
let deltaA =
(ro, t) ->
(rg, t) ->
(gr, t) ->
(ge, t) ->
(aa, t) ->
(ro, n) ->
(rg, n) ->
(gr, n) ->
(ge, n) ->
(aa, n) ->
function
rg |
gr |
ge |
ro |
ge |
aa |
aa |
aa |
aa |
ge ;;
let lambdaA = function
(ro, t) -> OOo |
(rg, t) -> ooO |
(gr, t) -> oOo |
...
Funktionale Programmierung
17
KB
Teil 2
Kontrollstrukturen
Zielsetzung
18
Funktionale Programmierung
0
KB
0
1
00011011
Ok!
g
u
1
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.
Listen
19
Funktionale Programmierung
0
KB
0
1
[0; 0; 0; 1; 1; 0; 1; 1]
g
true
u
1
Eine Liste in Caml besteht aus einer beliebigen, aber endlichen
Anzahl von Elementen, die alle den gleichen Typ haben.
Listenkonstruktoren
20
Leere Liste:
Funktionale Programmierung
Die leere Liste wird mit [] dargestellt.
KB
Hinzufügen eines Elementes:
Mit Hilfe des Hinzufügoperators :: kann ein Element vorne in eine
Liste eingefügt werden.
Bsp.: 1 :: [2; 3]  [1; 2; 3]
21
Spezifikation des Automatensimulators
Funktionale Programmierung
Spezifikation:
simulatorP
Zustand
Zustand nach der
Verarbeitung der Eingaben
Eingabeliste
Bsp.: simulatorP(g, [e0; e1; e1; e1])  u
Spezifikation:
akzeptorP
Eingabeliste
Bsp.: akzeptorP([e0; e1; e1; e1])  false
KB
true / false
22
Rekursive Problemreduktion
Fall 1: Verarbeite eine leere Eingabenliste
Funktionale Programmierung
simulartorP(g, [])  g
Fall 2: Verarbeite eine nicht-leere Eingabenliste
simulatorP(g, [e1; e0; e1])  simulatorP(u, [e0; e1])]
g
g
Rekursive Problemreduktion: Reduktion des Problems auf ein
entsprechendes, aber „verkleinertes“ Problem
KB
Reduktionsregeln
23
Fall 1: Verarbeite eine leere Eingabenliste
Funktionale Programmierung
simulartorP(g, [])  g
KB
Fall 2: Verarbeite eine nicht-leere Eingabenliste
simulatorP(g, [e1; e0; e1])  simulatorP(u, [e0; e1])]
g
g
let rec simulatorP = function
(z, [])
-> z |
(z, e::r) -> simulatorP(deltaP(e,z), r);;
Reduktionsketten
Funktionale Programmierung
24
let rec simulatorP = function
(z, [])
-> z |
(z, e::r) -> simulatorP(deltaP(e,z), r);;
simulatorP(g, [e1; e0; e1]) 
simulatorP(deltaP(g, e1), [e0; e1]) 
simulatorP(delta(deltaP(g, e1), e0), [e1]) 
simulatorP(delta(delta(deltaP(g, e1), e0), e1), []) 
delta(delta(deltaP(g, e1), e0), e1) 
delta(delta(u, e0), e1) 
delta(u, e1) 
g
Caml berechnet mit Hilfe solcher Reduktionsketten den Wert des
Ausgangsterms.
KB
25
Paritäts-Akzeptor
Funktionale Programmierung
#simulatorP : zustandP * eingabeP list -> zustandP =
<fun>
KB
#akzeptorP : eingabeP list -> bool = <fun>
let rec simulatorP = function
(z, [])
-> z |
(z, e::r) -> simulatorP(deltaP(z,e), r);;
let akzeptorP = function
w -> endzustandP(simulatorP(anfangszustandP,w));;
26
Test des Akzeptors
#akzeptorP([e1;e0;e1]);;
Funktionale Programmierung
- : bool = true
KB
akzeptorP([e1;e0;e1]);;
27
Kontrollstrukturen
Funktionale Programmierung
Fallunterscheidung
KB
let rec simulatorP = function
(z, [])
-> z |
(z, e::r) -> simulatorP(deltaP(e,z), r);;
Rekursion
let akzeptorP = function
w -> endzustandP(simulatorP(anfangszustandP,w));;
Funktionskomposition
Funktionsdeklarationen werden mit Hilfe von
- Funktionskomposition,
- Fallunterscheidungen und
- Rekursion
aufgebaut.
Übung
28
Funktionale Programmierung
Spezifikation:
KB
simulatorA
Zustand
Eingabeliste
Liste mit den erzeugten
Ausgaben
Bsp.: simulatorA(ro, [t; t; t; t])  [OOo; ooO; oOo; Ooo]
Entwickeln Sie eine Funktionsdeklaration zur Implementierung
eines Ampelsimulators.
Lösungsvorschlag
29
#simulatorA : zustandA * eingabeA list -> ausgabeA list =
<fun>
Funktionale Programmierung
#- : ausgabeA list = [Ooo; OOo; ooO; ooO; ooo; oOo]
KB
...
(* Deklaration der Ampel *)
...
let rec simulatorA = function
(z, [])
-> [] |
(z, e::r) -> lambdaA(z,e) :: simulatorA(deltaA(z,e), r);;
simulatorA(anfangszustandA, [t;t;t;t;n;n]);;
Funktionale Programmierung
30
KB
Teil 3
Datenstrukturen
Zielsetzung
31
Funktionale Programmierung
let anfangszustandP = g;;
KB
let endzustandP = function
g -> true | u -> false;;
let deltaP = function
(g, e0) -> g | (g, e1) -> u |
(u, e0) -> u | (u, e1) -> g ;;
Ok!
00011011
Es soll ein universelles Akzeptor-System entwickelt werden, mit
dem eine Folge von Eingaben mit einem beliebig vorgegebenen
Automaten verarbeiten werden kann.
32
Spezifikation des Automatensimulators
Spezifikation:
Funktionale Programmierung
simulator
Automatenbeschreibung
Zustand nach der
Verarbeitung der Eingaben
Zustand
Eingabeliste
Bsp.: simulator((g, (g  true, u  false), ...), g, [e0; e1; e1; e1])  u
Spezifikation:
akzeptor
Automatenbeschreibung
Eingabeliste
true / false
Bsp.: akzeptor((g, (g  true, u  false), ...), [e0; e1; e1; e1])  false
KB
Automatenbeschreibung
33
Spezifikation:
Funktionale Programmierung
simulator
KB
Automatenbeschreibung
Zustand
Eingabeliste
Zustand nach der
Verarbeitung der Eingaben
Bsp.: simulator((g, (g  true, u  false), ...), g, [e0; e1; e1; e1])  u
Eine Automatenbeschreibung ist ein Tripel (az, ez, de) mit:
- az ist eine Konstante eines Zustandstyps 'a („Anfangszustand“).
- ez ist eine Funktion 'a  'b, die jedem Zustand aus 'a einen
Wert aus 'b zuordnet („Endzustand“).
- de ist eine Funktion 'a * 'c  'a, die jedem Zustand aus 'a
und jeder Eingabe aus einem Eingabetyp 'c einen neuen Zustand
aus 'a zuordnet („Delta“).
34
Reduktionsregeln
Funktionale Programmierung
#simulator :
('a * 'b * ('c * 'd -> 'd)) * 'd * 'c list -> 'd
= <fun>
KB
#akzeptor :
('a * ('a -> 'b) * ('c * 'a -> 'a)) * 'c list -> 'b
= <fun>
let rec simulator = function
((az,ez,de), z, [])
-> z |
((az,ez,de), z, e::r) ->
simulator((az,ez,de), de(z,e), r);;
let akzeptor = function
((az,ez,de), w) -> ez(simulator((az,ez,de), az, w));;
Test
35
#akzeptor(automatP, wortP);;
Funktionale Programmierung
- : bool = false
let rec simulator = function ...
let akzeptor = function ...
type zustandP = g | u;;
type eingabeP = e0 | e1;;
let anfangszustandP = g;;
let endzustandP = function
g -> true | u -> false;;
let deltaP = function
(g,e0)->g| (g,e1)->u| (u,e0)->u| (u,e1)->g;;
let automatP = (anfangszustandP, endzustandP, deltaP);;
let wortP = [e0; e1; e1; e1];;
KB
akzeptor(automatP, wortP);;
Datenstrukturen
Funktionale Programmierung
36
KB
let rec simulator = function
((az,ez,de), z, [])
-> z |
((az,ez,de), z, e::r) -> simulator(...);;
Funktion
Tupel
Liste
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.
Übung
37
Spezifikation:
Funktionale Programmierung
simulator
KB
Automatenbeschreibung
Zustand
Eingabeliste
Liste mit den erzeugten
Ausgaben
Bsp.: simulator((...), ro, [t; t; t; t])  [OOo; ooO; oOo; Ooo]
Entwickeln Sie eine Funktionsdeklaration zur Implementierung
eines Automatensimulators. Testen Sie den Simulator.
38
Lösungsvorschlag
Funktionale Programmierung
#simulator : ('a * ('b * 'c -> 'b) * ('b * 'c -> 'd)) * 'b *
'c list -> 'd list = <fun>
#transduktor : ('a * ('a * 'b -> 'a) * ('a * 'b -> 'c)) * 'b
list -> 'c list = <fun>
#ampel : zustandA * (zustandA * eingabeA -> zustandA) *
(zustandA * eingabeA -> ausgabeA) = ge, <fun>, <fun>
#- : ausgabeA list = [Ooo; OOo; ooO; oOo; ooo; oOo]
... (* Deklaration der Ampel *) ...
let rec simulator = function
((az, de, la), z, [])
-> [] |
((az, de, la), z, e::r) ->
la(z,e) :: simulator((az, de, la), de(z,e), r);;
let transduktor = function
((az, de, la), w) -> simulator((az, de, la), az, w);;
let ampel = (anfangszustandA, deltaA, lambdaA);;
transduktor(ampel, [t;t;t;t;n;n]);;
KB
Funktionale Programmierung
39
KB
Teil 4
Deklarative Programmierung
Funktionale Programmierung
40
Programmierstile
begin
automat.anfangszustand;
for i := 0 to eingaben.Count-1 do
begin
e := eingaben[i];
a := automat.ausgabe(e);
automat.neuerZustand(e);
ausgaben.Add(a);
end;
end;
Programmierung mit
Wertzuweisungen
Programmierung mit
let rec simulator = function
Funktionsdeklarationen
((az, de, la), z, [])
-> [] |
((az, de, la), z, e::r) ->
la(z,e) :: simulator((az, de, la), de(z,e), r);;
let transduktor = function
((az, de, la), w) -> simulator((az, de, la), az, w);;
let ampel = (anfangszustandA, deltaA, lambdaA);;
KB
transduktor(ampel, [t;t;t;t;n;n]);;
Funktionale Programmierung
41
KB
Imperative Programmierung
begin
z := anfangszustand;
for i := 0 to n-1 do
begin
e := eingaben[i];
a := ausgabe(e);
z := neuerZustand(e);
ausgaben[i] := a;
end;
end;
Programmierung mit
Wertzuweisungen
Wertzuweisungen sind die zentralen elementaren Bausteine
imperativer Programme. Die Wertzuweisungen verändern (i. a.)
den momentanen Variablenzustand (Speicherzustand).
Imperative Programmierung
42
Funktionale Programmierung
Beschreiben, wie die Ergebnisse berechnet werden sollen.
KB
A.-Zustand
Anweisungen
E.-Zustand
{eingaben: [t][t][t][t]}
z := anfangszustand;
for i := 0 to n-1 do
begin
e := eingaben[i];
a := ausgabe(e);
z := neuerZustand(e);
ausgaben[i] := a;
end;
Registermaschine
{ausgaben: [Ooo][OOo][ooO][oOo]}
Imperative Programmierung besteht darin, eine mehr oder
weniger abstrakte Registermaschine (Maschine mit
Speicherzellen) mit Hilfe von Anweisungen zu steuern.
Vorsicht: Seiteneffekte
43
PROGRAM Demo;
Funktionale Programmierung
VAR d: boolean;
w1, w2: integer;
KB
function f(n: int.): int.;
BEGIN
if d THEN
f := 2*n
ELSE
f := n;
d := not d;
END;
BEGIN
d := true;
w1 := f(1)+f(2);
w2 := f(2)+f(1);
END.
{d:
; w1:
; w2:
}
d := true;
{d: true; w1:
w1 :=
f(1)
; w2:
+
2
f(2) ;
2
{d: true; w1: 4; w2:
w1 :=
f(2)
}
+
}
f(1) ;
4
1
{d: true; w1: 4; w2: 5}
Seiteneffekt: Veränderung
einer globalen Variablen
Imperative Programmierung ist wegen der Möglichkeit,
Seiteneffekte zu produzieren, recht fehleranfällig.
Funktionale Programmierung
44
KB
Funktionale Programmierung
let rec simulator = function
((az, de, la), z, [])
-> [] |
((az, de, la), z, e::r) ->
la(z,e) :: simulator((az, de, la), de(z,e), r);;
let transduktor = function
((az, de, la), w) -> simulator((az, de, la), az, w);;
let ampel = (anfangszustandA, deltaA, lambdaA);;
transduktor(ampel, [t;t;t;t;n;n]);;
Programmierung mit
Funkionsdeklarationen
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.
Funktionale Programmierung
45
Funktionale Programmierung
Beschreiben, was (welche funkt. Zusammenhänge) gelten soll.
KB
A.-Term
transduktor(ampel,[t;t;t]);;
...
Deklarationen
let rec simulator = function
((az,de,la),z,[]) ->[]|
((az,de,la),z,e::r)->...
Reduktionsmaschine
...
E.-Term
#- : ausgabeA list =
[Ooo; OOo; ooO]
Funktionale Programmierung besteht darin, die strukturellen
Zusammenhänge der Miniwelt mit Hilfe von Funktionen zu
beschreiben.
Funktionale Programmierung
46
KB
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“.
Prototyp eines Automatensimulationsprogramms:
let rec simulator = function
((az, de, la), z, [])
-> [] |
((az, de, la), z, e::r) ->
la(z,e) :: simulator((az, de, la), de(z,e), r);;
let transduktor = function
((az, de, la), w) -> simulator((az, de, la), az, w);;
47
Literaturhinweise
Funktionale Programmierung
[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)
[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.
[MacLennan ??] B.J. MacLennan: Functional Programming: Addison-Wesley ??.
[Wagenknecht 94] Christian Wagenknecht: Rekursion. Ein didaktischer Zugang
mit Funktionen. Bonn: Dümmlers Verlag 1994.
KB
[Wolff von Gudenberg 96] J. Wolff. von Gudenberg: Algorithmen,
Datenstrukturen, Funktionale Programmierung. Eine praktische Einführung mit
Caml Light. Bonn: Addison-Wesley 1996.
Herunterladen