Die Präsentation wird geladen. Bitte warten

Die Präsentation wird geladen. Bitte warten

Funktionale Programmierung mit Caml

Ähnliche Präsentationen


Präsentation zum Thema: "Funktionale Programmierung mit Caml"—  Präsentation transkript:

1 Funktionale Programmierung mit Caml
Klaus Becker 2004

2 Programmieren mit Funktionen
akzeptor 1 g u Ok! 1

3 Funktionen als Programme
Teil 1 Funktionen als Programme

4 Die Welt der Automaten 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
1 g u 1 Zustandsmenge: Z = {g, u} Anfangszustand: za = g Endzustände: zE = {g} Eingabemenge: E = {0, 1} Überführungsfunktion: : (g, 0)  g : (g, 1)  u : (u, 0)  u : (u, 1)  g

6 Funktionale Modellierung
Zustandsmenge: Z = {g, u} Eingabemenge: E = {0, 1} Anfangszustand: za = g Endzustände: zE = {g} Überführungsfunktion: : (g, 0)  g : (g, 1)  u : (u, 0)  u : (u, 1)  g 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 ;;

7 Funktionale Modellierung
anfangszustandP endzustandP: g  true deltaP: (g, e1)  u g u g u true false g u e0 e1 zustand zustand bool zustand eingabe 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 ;;

8 Modellierungskonzept
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 ;; Typdeklaration Konstantendeklaration Funktionsdeklaration 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. #Type eingabeP defined. #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

10 Funktionsdeklaration
Signaturanalyse Signatur der Funktion Auswertung: #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

11 Funktionsanwendung Auswertung: ... #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: deltaP(u, e0);; Vorherige Benutzereingaben: type zustandP = g | u;; type eingabeP = e0 | e1;; ... let deltaP = function (g, e0) -> g | (g, e1) -> u | (u, e0) -> u | (u, e1) -> g ;;

12 Funktionsanwendung Die Auswertung des funktionalen Ausdrucks
#endzustandP(deltaP(deltaP(anfangszustandP, e1), e1));; - : 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.

13 Funktionale Programme
Ein funktionales Programm besteht aus einer Menge von Funktionsdeklarationen (und evtl. benötigten Typdeklarationen) und einem funktionalen Ausdruck (Berechnungsausdruck). Funktionaler Ausdruck Funktionsdeklarationen Benutzereingabe: deltaP(u, e0);; Benutzereingabe: type zustandP = g | u;; type eingabeP = e0 | e1;; ... let deltaP = function (g, e0) -> g | (g, e1) -> u | (u, e0) -> u | (u, e1) -> g ;;

14 Programmierkonzept type zustandP = g | u;; 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.

15 Übung Entwickeln Sie ein funktionales Programm zur Simulation einer Ampelschaltung mit Tag-Nacht-Betrieb. Testen Sie das Programm.

16 Lösungsvorschlag type zustandA = ro | rg | ge | gr | aa;;
type eingabeA = t | n;; type ausgabeA = Ooo | OOo | ooO | oOo | ooo;; let anfangszustandA = ge;; let deltaA = function (ro, t) -> rg | (rg, t) -> gr | (gr, t) -> ge | (ge, t) -> ro | (aa, t) -> ge | (ro, n) -> aa | (rg, n) -> aa | (gr, n) -> aa | (ge, n) -> aa | (aa, n) -> ge ;; let lambdaA = function (ro, t) -> OOo | (rg, t) -> ooO | (gr, t) -> oOo | ...

17 Teil 2 Kontrollstrukturen

18 Zielsetzung 1 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.

19 Listen 1 [0; 0; 0; 1; 1; 0; 1; 1] true g u 1 Eine Liste in Caml besteht aus einer beliebigen, aber endlichen Anzahl von Elementen, die alle den gleichen Typ haben.

20 Listenkonstruktoren Leere Liste:
Die leere Liste wird mit [] dargestellt. 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
simulatorP Zustand Zustand nach der Verarbeitung der Eingaben Eingabeliste Bsp.: simulatorP(g, [e0; e1; e1; e1])  u Spezifikation: akzeptorP Eingabeliste true / false Bsp.: akzeptorP([e0; e1; e1; e1])  false

22 Rekursive Problemreduktion
Fall 1: Verarbeite eine leere Eingabenliste 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

23 Reduktionsregeln Fall 1: Verarbeite eine leere Eingabenliste
simulartorP(g, [])  g 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);;

24 Reduktionsketten 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.

25 Paritäts-Akzeptor #simulatorP : zustandP * eingabeP list -> zustandP = <fun> #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]);; - : bool = true

27 Funktionskomposition
Kontrollstrukturen Fallunterscheidung let rec simulatorP = function (z, []) -> z | (z, e::r) -> simulatorP(deltaP(e,z), r);; let akzeptorP = function w -> endzustandP(simulatorP(anfangszustandP,w));; Rekursion Funktionskomposition Funktionsdeklarationen werden mit Hilfe von - Funktionskomposition, - Fallunterscheidungen und - Rekursion aufgebaut.

28 Übung Spezifikation: simulatorA
Zustand Liste mit den erzeugten Ausgaben Eingabeliste Bsp.: simulatorA(ro, [t; t; t; t])  [OOo; ooO; oOo; Ooo] Entwickeln Sie eine Funktionsdeklaration zur Implementierung eines Ampelsimulators.

29 Lösungsvorschlag #simulatorA : zustandA * eingabeA list -> ausgabeA list = <fun> #- : ausgabeA list = [Ooo; OOo; ooO; ooO; ooo; oOo] ... (* 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]);;

30 Teil 3 Datenstrukturen

31 Zielsetzung 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 ;; Ok! 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
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 true / false Eingabeliste Bsp.: akzeptor((g, (g  true, u  false), ...), [e0; e1; e1; e1])  false

33 Automatenbeschreibung
Spezifikation: simulator Automatenbeschreibung Zustand nach der Verarbeitung der Eingaben Zustand Eingabeliste 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 #simulator : ('a * 'b * ('c * 'd -> 'd)) * 'd * 'c list -> 'd = <fun> #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));;

35 Test #akzeptor(automatP, wortP);; - : 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];; akzeptor(automatP, wortP);;

36 Datenstrukturen 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 zusammen-gefasst werden. Funktionen können als Eingabeobjekte für weitere Funktionen benutzt werden.

37 Übung Spezifikation: simulator
Automatenbeschreibung Liste mit den erzeugten Ausgaben Zustand Eingabeliste 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 #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]);;

39 Deklarative Programmierung
Teil 4 Deklarative Programmierung

40 Programmierstile Programmierung mit Wertzuweisungen
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 Funktionsdeklarationen 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]);;

41 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).

42 Imperative Programmierung
Beschreiben, wie die Ergebnisse berechnet werden sollen. A.-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; Register-maschine Anweisungen E.-Zustand {ausgaben: [Ooo][OOo][ooO][oOo]} Imperative Programmierung besteht darin, eine mehr oder weniger abstrakte Registermaschine (Maschine mit Speicherzellen) mit Hilfe von Anweisungen zu steuern.

43 Vorsicht: Seiteneffekte
PROGRAM Demo; VAR d: boolean; w1, w2: integer; 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: ; w2: } w1 := f(1) + f(2) ; {d: true; w1: 4; w2: } w1 := f(2) + f(1) ; {d: true; w1: 4; w2: 5} 2 2 4 1 Seiteneffekt: Veränderung einer globalen Variablen Imperative Programmierung ist wegen der Möglichkeit, Seiteneffekte zu produzieren, recht fehleranfällig.

44 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.

45 Funktionale Programmierung
Beschreiben, was (welche funkt. Zusammenhänge) gelten soll. A.-Term transduktor(ampel,[t;t;t]);; ... let rec simulator = function ((az,de,la),z,[]) ->[]| ((az,de,la),z,e::r)->... Reduktions-maschine Deklarationen #- : ausgabeA list = [Ooo; OOo; ooO] E.-Term Funktionale Programmierung besteht darin, die strukturellen Zusammenhänge der Miniwelt mit Hilfe von Funktionen zu beschreiben.

46 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 [Becker 99] K. Becker: Funktionale Programmierung. Materialien zum Lehrplan Informatik. LMZ (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 [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 [Schwill 93] A. Schwill: Funktionale Programmierung mit Caml. In: LOG IN 13 (1993) Heft 4, S [MacLennan ??] B.J. MacLennan: Functional Programming: Addison-Wesley ??. [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.


Herunterladen ppt "Funktionale Programmierung mit Caml"

Ähnliche Präsentationen


Google-Anzeigen