Einführung in die Informatik II SS 2011 7 Funktionale Programmierung Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 1 7 Funktionale Programmierung ... Lernziele Verständnis funktionaler Porgrammierkonzepte Funktionen als Werte, Funktionen höherer Ordnung, Polymorphismus, ... Auseinandersetzung mit einem nicht-imperativen Programmierparadigma neue Sicht- und Denkweise! Vertieftes Verständnis der Rekursion Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 2 7 Funktionale Programmierung ... Literatur [Er99], Kap. 1, 2 [Kr02], Kap. 2, 3, 4 [Pa00], Kap. 1, 2, 4(.1), 7(.1), 8(.1) S. Sabrowski, Schnelleinstieg in Standard ML of New Jersey, 1996. http://www-pscb.informatik.tu-cottbus.de/~wwwpscb/studenten/sml.ps http://www.bs.informatik.unisiegen.de/web/wismueller/vl/gen/ei2/sml.pdf E. Januzaj, SML zum Mitnehmen – Eine Kurzreferrenz von SML-Funktionen www.dbs.informatik.uni-muenchen.de/Lehre/Info1/smlref/SMLKurzreferenz pdf 2.pdf Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 3 7 Funktionale Programmierung ... Inhalt Konzepte funktionaler Programmiersprachen SML: Überblick Werte und Ausdrücke Tupel, Records und Listen Variablen und Funktionen Typen und Polymorphismus Datentypen und Pattern Matching Funktionen höherer Ordnung Problemlösung mit Rekursion Auswertung funktionaler Programme Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 4 7.1 Konzepte funktionaler Programmiersprachen Besonderheiten funktionaler Programmiersprachen: Sie basieren auf dem Funktionsbegriff der Mathematik ein Programm ist eine Funktion, die aus anderen Funktionen zusammengesetzt ist Es gibt keine Variablen, deren Wert verändert werden kann der Variablenbegriff entspricht dem der Mathematik es gibt keine Zuweisungen eine Variable hat an allen Stellen innerhalb ihres Gültigkeitsbereichs immer denselben Wert (referenzielle Transparenz) Es gibt weder programmierten Kontrollfluß noch Seiteneffekte keine Anweisungsfolgen, keine Schleifen, ... eine Funktion liefert mit identischen Parametern immer dasselbe Ergebnis Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 5 7.1 Konzepte funktionaler Programmiersprachen ) (Mathematische) Funktionen Eine Funktion f von A in B ordnet jedem Element aus der Menge A genau ein Element aus der Menge B zu A ist der Definitionsbereich, B der Wertebereich von f f kann definiert werden durch: eine Aufzählung von Wertepaaren aus A × B eine Funktionsgleichung, z.B. f(x) = sin(x)/x Eine Funktionsgleichung führt auf der linken Seite Variablen ein, die für Werte aus dem Definitionsbereich stehen hat auf der rechten Seite einen Ausdruck aus Variablen, Konstanten und Funktionen Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 6 7.1 Konzepte funktionaler Programmiersprachen ) Funktionen: Begriffe und Schreibweisen A → B ist die Menge aller Funktionen von A in B Ist f ∈ A → B, schreiben wir auch f : A → B Für f : A → B liefert die Funktionsanwendung (Applikation) von f auf ein Argument a ∈ A das vermöge f zugeordnete Element aus B Schreibweisen für die Funktionsanwendung: f(a) Funktionsschreibweise fa Präfixschreibweise a1fa2 Infixschreibweise, falls A = A1 × A2, (a1, a2) ∈ A Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 7 7.1 Konzepte funktionaler Programmiersprachen ) Funktionen als Werte Eine Funktion f : A → B ist ein Wert der Menge A → B genauso, wie 5,2 ein Wert der Menge R ist Damit können Funktionen als Argumente an andere Funktionen übergeben werden und als Funktionsergebnis auftreten Dies führt zu Funktionen höherer Ordnung Beispiel: Funktionskomposition ◦ Der Operator ◦ ist eine Funktion aus der Menge (B → C) × (A → B) → (A → C) Funktionsgleichung für ◦: (f ◦ g)(x) = f(g(x)) Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 8 7.1 Konzepte funktionaler Programmiersprachen ) Referentielle Transparenz Jedes Vorkommen einer Variable (innerhalb ihres Gültigkeitsbereichs) bezeichnet denselben Wert Die Semantik hängt nicht wie bei imperativen Sprachen von einem impliziten Zustand (= Speicherbelegung) ab Mathematisch ist ein Ausdruck wie i = i + 1 sinnlos Gleichung ohne Lösung (0 = 1) Referentielle Transparenz erlaubt es immer, Variable durch ihre Definition zu ersetzen, ohne die Semantik zu ändern die Auswertung funktionaler Programme basiert genau auf diesem Prinzip dadurch lassen sich Eigenschaften funktionaler Programme einfach(er) beweisen (→Bedeutung der funkt. Prog.) Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 9 7.1 Konzepte funktionaler Programmiersprachen ) Kein programmierter Kontrollfluß In funktionalen Programmen gibt es keine Anweisungen keine Zuweisungen, Anweisungsfolgen, Schleifen, bedingte Anweisungen, ... Stattdessen: Rekursion und bedingte Ausdrücke Beispiel: Berechnung der Fakultät von n (= 1 2 ... n) die Funktionsgleichung schreibt die Art und Weise (z.B. die Reihenfolge) der Berechnung nicht vor! Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 10 7.1 Konzepte funktionaler Programmiersprachen ) Strukturen funktionaler Programme Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 11 7.2 SML: Überblick SML = Standard ML = Standard Meta Language ML wurde 1973 als Teil eines Theorembeweisers entwickelt seither viele Dialekte, 1984 ”standardisierte“ Version SML Referenzimplementierung: ”SML of New Jersey“ (SML/NJ) interaktiver Compiler für SML frei erhältlich für Windows und Linux (http://www.smlnj.org/) Eigenschaften von SML streng getypte funktionale Sprache polymorphes Typsystem Syntax nahe an mathematischer Notation enthält auch imperative Konstrukte (in der Vorlesung nicht behandelt) Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 12 7.2 SML: Überblick ) Interaktiver Compiler SML/NJ Start mit Kommando sml Ausgabe des Compilers (auf Folien rot und kursiv): Standard ML of New Jersey v110.57 [built: Wed Feb ...] Das Promptzeichen - zeigt, daß der Compiler eine Eingabe erwartet abgeschlossen mit ; und Enter-Taste Beispiel: - 5 + 10; val it = 15 : int it ist eine Variable (vom Typ int), die das Ergebnis der letzten Berechnung (15) bezeichnet Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 13 7.2 SML: Überblick ) Interaktiver Compiler SML/NJ ... Das Promptzeichen = zeigt unvollständige Eingabe an Beispiel: -5 = + 10; val it = 15 : int Eine Eingabe kann auch durch Drücken von Control-C abgebrochen werden Der Compiler wird durch Drücken von Control-D auf der obersten Ebene (Prompt: - ) beendet - ~5 = + 10; val it = 5 : int Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 14 7.2 SML: Überblick ) Eingaben können sein: Vereinbarungen von Variablen für Werte (einschließlich Funktionen), z.B. val x = 42 (-x; val it = 42 : int) ; oder fun f(x) = x+1; (val f = fn : int -> int) (- f(10); val it = 11 : int) Ausdrücke, z.B. x - 40; oder f x; Sie werden jeweils durch Semikolon voneinander getrennt Der Compiler prüft die Eingaben auf korrekte Syntax, übersetzt sie und führt sie ggf. sofort aus Die Ausgabe des Compilers ist immer eine Liste der vereinbarten Variablen (mit Angabe von Wert und Typ) - val x = 42; val y = 5; val x = 42 : int val y = 5 : int spezielle Variable ist für Ergebnis des letzten Ausdrucks Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 15 7.2 SML: Überblick ) SML-Programme können auch in Dateien abgelegt werden Einlesen in den Compiler: - use "beispiel.sml"; ←Datei enthält: val x = 42; [opening beispiel.sml] val x = 42 : int ←Ergebnis der Funktion use val it = () : unit - x + 2; val it = 44 : int Alternative: Aufruf des Compilers mit Dateiname sml beispiel.sml Syntax für Kommentare: (* Das ist ein Kommentar *) Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 16 7.2 SML: Überblick ) Fehlermeldungen des Compilers Beim Einlesen aus einer Datei: - use "beispiel.sml" [opening beispiel.sml] beispiel.sml:1.6-1.11 Error: unbound variable or ... ↑ Ort des Fehlers: Zeile.Spalte - Zeile.Spalte die Datei enthielt 1234-hallo; Bei interaktiver Eingabe: Zeilennummern teilweise unsinnig - 1234-hallo; stdIn:1.6-5.4 Error: unbound variable or constructor Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 17 7.3 Werte und Ausdrücke Werte sind Ausdrücke, die nicht weiter ausgewertet werden können einfache Werte: z.B. Zahlen, Zeichenketten, ... konstruierte Werte: z.B. Tupel, Listen, ... Funktionen, mit der Besonderheit: sie können auf andere Werte angewandt werden Alle Werte haben in SML einen eindeutig bestimmten Typ Werte, die keine Funktionen sind oder enthalten, heißen Konstante Aus Werten (incl. Funktionen) können Ausdrücke geformt werden, die bei der Auswertung auf Werte reduziert werden d.h. Auswertung im Sinne mathematischer Vereinfachung Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 18 7.3 Werte und Ausdrücke ) Ganze Zahlen (int) Übliche Darstellung, negative Zahlen aber mit vorangestellter Tilde (~), z.B. 13, ~5 Vordefinierte Funktionen auf ganzen Zahlen: binäre Operationen: +, -, *, div, mod zweistellige Funktionen in Infixschreibweise vom Typ int * int -> int (math.: Z × Z → Z) unäre Operationen: ~, abs (Negation, Absolutbetrag) einstellige Funktionen in Pr äfixschreibweise vom Typ int -> int (math.: Z → Z) * und -> sind Typkonstruktoren zur Bildung neuer Typen (kartesisches Produkt bzw. Funktionstyp) aus vorhandenen Typen Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 19 7.3 Werte und Ausdrücke ) Zur Funktionsapplikation Die Applikation hat höchste syntaktische Priorität d.h. abs 4-5 bedeutet (abs 4) - 5 die Klammern bei z.B. f(x+y) sind normale Klammern um den Ausdruck x+y, auf dessen Wert f angewandt wird Die Applikation ist linksassoziativ d.h. f g x bedeutet (f g) x Beispiel: - ~ abs(4-5); stdIn:1.1 Error: overloaded variable not defined at type symbol: ~ type: int -> int Versuch, die Funktion ~ auf die Funktion abs anzuwenden Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 20 7.3 Werte und Ausdrücke ) Reelle Zahlen (real) Übliche Darstellung, aber mit ~ statt -, z.B. 3.0, ~5E2, 0.5E~3 Die Operationen +, -, *, ~ und abs sind auch auf rellen Zahlen definiert (d.h. sie sind überladen) Division: / (Typ: real * real -> real) Umwandlung zwischen int und real: real: int -> real floor: real -> int größte ganze Zahl ≤ Argument (- floor 3.4; / val it = 3 : int) Keine implizite Typumwandlung: - 3.0 * 4; stdIn:1.1-6.3 Error: operator and operand don’t agree operator domain: real * real operand: real * int Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 21 7.3 Werte und Ausdrücke ) Zeichenketten (string) und Zeichen (char) Übliche Darstellung für Strings, z.B. "Ein String" (val it = „Ein String“ : string) Darstellung für Zeichen: #"a" Funktionen für Strings: ^: string * string -> string Konkatenation size: string -> int Länge substring: string * int * int -> string Teilstring, Argumente: Startposition (ab 0) und Länge Beispiel: - substring ("abcd" ^ "efgh", 2, 4); val it = "cdef" : string - substring("ab",2,1); uncaught exception Subscript [subscript out of bounds] Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 22 7.3 Werte und Ausdrücke ) Wahrheitswerte (bool) Konstanten: true, false Operationen: not (Negation), andalso (Und), orelse (Oder) das zweite Argument von andalso bzw. orelse wird nur ausgewertet, falls notwendig Vergleichsoperationen (mit Ergebnis vom Typ bool): =, <> für int, char, string und bool <, <=, >, >= für int, real, char und string Fallunterscheidung (ternäre Funktion): if ... then ... else ... - val n = 2; val n = 2 : int - (if n<>0 then 100 div n else 0) + 10; val it = 60 : int Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 23 7.4 Tupel, Records und Listen Tupel, Records und Listen fassen mehrere Werte zu einer Einheit zusammen Tupel feste Zahl von Werten, auch mit unterschiedlichen Typen Zugriff auf Komponenten über Positionsindex Record: feste Zahl von Werten, auch mit unterschiedlichen Typen Zugriff auf Komponenten über beliebige Identifikatoren oder ganze Zahlen d.h. Tupel sind spezielle Records Liste beliebige, variable Zahl von Werten desselben Typs Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 24 7.4 Tupel, Records und Listen ) 7.4.1 Tupel Schreibweise / Konstruktion von Tupeln: ( [ <Ausdruck> {, <Ausdruck>} ] ) Beispiele: - (1-1, true, 5.0, 2<1); val it = (0,true,5.0,false) : int * bool * real * bool - (2); val it = 2 : int einstellige Tupel bilden keinen eigenständiger Typ - (); val it = () : unit das nullstellige Tupel hat den Typ unit, der () als einzigen Wert besitzt Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 25 7.4.1 Tupel ... Selektion von Komponenten Komponenten eines Tupels können über ihre Position selektiert werden (Zählung ab 1) Operator # <IntKonstante> <Ausdruck> Beispiele: - #1 (1-1, true, 5.0, 2<1); val it = 0 : int - #1 (#2 (1.1,(2,3.3))); val it = 2 : int Tupel können auch wieder Tupel enthalten - #3 (1,2); stdIn:15.1-15.9 Error: operator and operand don’t agree Compiler prüft Zulässigkeit des Selektors Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 26 7.4 Tupel, Records und Listen ... 7.4.2 Records Schreibweise / Konstruktion von Records: { [ <Name> = <Ausdruck> {, <Name> = <Ausdruck>} ] } Beispiele: - {Name="Joe",Age=35}; val it = {Age=35,Name="Joe"} : {Age:int, Name:string} die Reihenfolge der Komponenten spielt keine Rolle, die Komponentennamen gehören mit zum Typ - {2=7, true=false}; val it = {2=7,true=false} : {2:int, true:bool} Komponentennamen können beliebige Identifikatoren oder ganze Zahlen sein Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 27 7.4.2 Records ... Beispiele...: - {2=9,1=35,3="hallo"} = (35,9,"hallo"); val it = true : bool Records mit Komponentennamen 1...n werden als Tupel interpretiert Selektion von Komponenten Analog zu Tupeln über den Operator # Beispiele: - #Pos {Ort="Hagen", Pos=(1.0,2.3)}; val it = (1.0,2.3) : real * real - #r (#2 (3,{x=1,r=4})); val it = 4 : int Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 28 7.4 Tupel, Records und Listen ... 7.4.3 Listen Schreibweise / Konstruktion von Listen: [ [ <Ausdruck> {, <Ausdruck>} ] ] Beispiele: - [1,2,3,4]; val it = [1,2,3,4] : int list - [1,3.0]; stdIn:29.1-29.8 Error: operator and operand don’t agree alle Listenelemente müssen denselben Typ haben - []; val it = [] : ’a list leere Liste: der Typ enthält eine freie Typvariable (s. später) alternativ auch nil statt [] / (- nil ;) Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 29 7.4.3 Listen ... Operationen auf Listen Erstes Element der Liste (hd / head) und Restliste (tl / tail): - hd [1,2,3]; val it = 1 : int - tl [1,1+1]; val it = [2] : int list - tl [[1,2],[3],[]]; val it = [[3],[]] : int list list ←Ergebnis ist immer Liste! ←Liste von Listen Anfügen am Anfang der Liste: :: - 1 :: [2, hd[3]]; val it = [1,2,3] : int list Konkatenation zweier Listen: @ - [1,2] @ [3,4]; val it = [1,2,3,4] : int list Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 30 7.4.3 Listen ... Operationen auf Listen ... Umkehren einer Liste: rev - rev [1,2,3,4]; val it = [4,3,2,1] : int list (reverse bei LISP) - hd (rev [1,2,3,4]); val it = 4 : int ←letztes Element der Liste Umwandlung von string nach char list: explode - explode "Bombe"; val it = [#"B",#"o",#"m",#"b",#"e"] : char list Umwandlung von char list nach string: implode - implode (rev (explode "Bombe")); val it = "ebmoB" : string Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 31 7.5 Variablen und Funktionen 7.5.1 Variablen Eine Variable ist ein Bezeichner für einen Wert Die Zuordnung eines Werts zu einem Bezeichner heißt Bindung Bindung ist Paar (Bezeicher, Wert) Die Menge der aktuell existierenden Bindungen heißt Umgebung Die (Werte-)Definition val <Variable> = <Ausdruck> erzeugt eine neue Variablen-Bindung der Wert des Ausdrucks wird an die Variable gebunden Beispiel: - val Name = "Mi"^"ln"^"er"; val Name = "Milner" : string Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 32 7.5.1 Variablen ) Mehrfache Bindung Eine Variable kann nacheinander an verschiedene Werte (auch verschiedenen Typs) gebunden werden: - val bsp = 1234; val bsp = 1234 : int - bsp + 1; val it = 1235 : int - val bsp = ("Hallo", "Welt"); val bsp = ("Hallo","Welt") : string * string - #1 bsp; val it = "Hallo" : string auch die Variable it wird hier mehrfach gebunden Die Umgebung wird somit durch Definitionen verändert Beachte: die Werte haben einen Typ, nicht die Variablen! Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 33 7.5.1 Variablen ) Pattern Matching Eine Definition kann auch mehrere Variablen auf einmal binden linke und rechte Seite dürfen komplexe Werte mit gleicher Struktur sein Tupel, Records, Listen und selbst definierte Datentypen die Bindung der Variablen ergibt sich dann als Lösung der (einfachen) mathematischen Gleichung Beispiel: - val (x,y) = (3,2.0); val x = 3 : int val y = 2.0 : real - val {a=u,2=v} = {2="Hallo",a=43}; val v = "Hallo" : string val u = 43 : int Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 34 7.5 Variablen und Funktionen ... 7.5.2 Funktionen Funktionen (als Werte) werden in SML wie folgt dargestellt: fn <Variable> => <Ausdruck> Beispiel: fn x => 2 * x ist die Funktion, die jeder Zahl x ihr Doppeltes zuordnet Ein solcher Funktions-Wert kann auf andere Werte angewandt werden: - (fn x => 2 * x) 5; val it = 10 : int Er kann wie jeder andere Wert verwendet werden Bindung an Namen Speichern in Tupeln, Records oder Listen Argument oder Ergebnis von Funktionen Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 35 7.5.2 Funktionen ) Binden von Funktionswerten an Namen (Funktionsdeklaration) Syntax genau wie bei anderen Werten, z.B.: - val dbl = fn x => 2 * x; val dbl = fn : int -> int Compiler gibt statt des Werts nur fn aus Der Typ (hier: int -> int) wird automatisch aus der Funktionsgleichung (x => 2 * x) ermittelt (Typinferenz) Abkürzende Schreibweise: fun <Variable1> <Variable2> = <Ausdruck> <Variable1>: Funktions-Bezeichner, <Variable2>: Argument im Beispiel: - fun dbl x = 2 * x; val dbl = fn : int -> int Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 36 7.5.2 Funktionen ) Applikation von Funktionen Über den Funktions-Bezeichner: - dbl 5; val it = 10 : int - dbl (5+5); val it = 20 : int Direkte Anwendung eines Funktions-Werts auf einen anderen Wert: - (fn x => 2 * x) ((fn x => x + 1) 5); val it = 12 : int Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 37 7.5.2 Funktionen ) Typrestriktion Eine Funktion zum Quadrieren: - fun square x = x * x; val square = fn : int -> int Warum hat diese Funktion den Typ int -> int und nicht real -> real? der Operator * ist überladen für int und real die Typinferenz kann damit den notwendigen Typ des Arguments nicht eindeutig bestimmen SML wählt dann den Default-Typ, hier int SML erlaubt aber auch, den Typ eines Ausdrucks zu erzwingen (Typrestriktion) Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 38 7.5.2 Funktionen ) Typrestriktion ... Beispiele Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 39 7.5.2 Funktionen ) Funktionen mit mehreren Argumenten Eine (mathematische) Funktion hat genau ein Argument und genau ein Resultat Eine Funktion mit mehreren Argumenten ist genau betrachtet eine Funktion auf einem Tupel: - fun minimum (x,y) = if x<y then x else y; val minimum = fn : int * int -> int Ebenso kann eine Funktion auch ein Tupel von Werten als Resultat liefern: - fun DivMod (a,b) = (a div b, a mod b); val DivMod = fn : int * int -> int * int - DivMod (9,4); val it = (2,1) : int * int Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 40 7.5.2 Funktionen ) Pattern Matching Pattern Matching ist auch bei Funktionsargumenten möglich Dabei können mehrere alternative Muster angegeben werden Dies erlaubt z.B. die Funktionsdefinition durch Aufzählung: - fun f 0 = 0 =|f1=2 = | f 2 = 3; stdIn:27.5-29.10 Warning: match nonexhaustive val f = fn : int -> int Warnung, da Funktion nicht für alle int-Werte definiert wird Auch möglich: Ausnahmefälle und allgemeiner Fall - fun f 0 = 0 ←wird zuerst geprüft = | f n = n + 1; ←falls n 6= 0 Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 41 7.5.2 Funktionen ) Pattern Matching: Weitere Beispiele Eine Funktion muß jedoch einen wohldefinierten Typ haben: - fun f (x,y) = x + y = | f (x,y,z) = x + y + z; stdIn:1.5-59.26 Error: parameter or result constraint of clauses don’t agree [tycon mismatch] der Typ kann nicht gleichzeitig int * int -> int und int * int * int -> int sein Beispiel: Fakult ätsfunktion (rekursive Funktion) - fun fak 0 = 1 = | fak n = n * fak(n-1); val fak = fn : int -> int - fak 10; val it = 3628800 : int Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 42 7.5.2 Funktionen ) Pattern Matching: Funktionen auf Listen Länge einer Liste: - fun len [] = 0 = | len (x::rest) = 1 + len rest; val len = fn : ’a list -> int ←leere Liste ←Liste x :: rest die Klammern um x::rest sind notwendig die Funktion kann auf Listen beliebigen Typs (’a list) angewandt werden (polymorphe Funktion): - len [3,3,2,2]; val it = 4 : int - len ["hallo", "welt"]; val it = 2 : int - len [[],[1,2,3],[5,2]]; val it = 3 : int Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 43 7.5.2 Funktionen ... Pattern Matching: Funktionen auf Listen ... Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 44 7.5.2 Funktionen ... Pattern Matching: Funktionen auf Listen ... Ein Operator zum sortierten Einfügen in eine Liste: definiert einen neuen, rechtsassoziativen InfixOperator ++ mit Priorität 5 linksassoziative Operatoren werden mit infix definiert Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 45 7.5.2 Funktionen ... Pattern Matching: Funktionen auf Listen ... Sortiertes Einfügen in eine Liste von Gleitkommazahlen: Gesamtl änge einer Liste von Listen: Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 46 7.5.2 Funktionen ... Statisches Binden Was passiert mit glen, wenn wir len neu definieren? - fun len x = 0; val len = fn : ’a -> int - glen [[],[1,2,3],[5,2]]; val it = 5 : int Die neue Bindung für len hat keinen Einfluß auf glen Maßgeblich für die Semantik einer Funktion ist die Umgebung (d.h. die Bindungen) zum Zeitpunkt ihrer Definition, nicht die zum Zeitpunkt ihrer Auswertung (statisches Binden) Eigenschaft fast aller funktionaler Sprachen Eine einmal definierte Funktion verhält sich damit bei jedem Aufruf gleich Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 47 7.5.2 Funktionen ... Freie Variablen in Funktionsdefinitionen Funktionsgleichungen können auch Variablen enthalten, die keine Argumente sind (freie Variablen) diese Variablen müssen aber an ein Wert gebunden sein auch hier wird statisches Binden verwendet Beispiel: - val pi = 3.14159265; val pi = 3.14159265 : real - fun area r = pi * r * r; ←pi ist freie Variable val area = fn : real -> real - val pi = 0.0; ←neue Bindung für pi val pi = 0.0 : real - area 2.0; ←verwendet Bindung zum val it = 12.5663706 : real Zeitpunkt der Def. v. area Madjid Fathi Wissensbasierte Systeme / Wissensmanagement Einführung in die Informatik II 48 7.5.2 Funktionen ... Lokale Definitionen Manchmal sollen Definitionen nur lokal in einem Ausdruck gelten z.B. Einführen einer Variable als Abkürzung für einen Term SML bietet dazu let-Ausdrücke an: let <Deklarationsfolge> in <Ausdruck> end die lokalen Deklarationen ver ändern die Umgebung außerhalb des let-Ausdrucks nicht! Beispiel: - val x = 1; val x = 1 : int ↓ x aus der Umgebung (mit Wert 1) - val res = let val x = x+1 in x * x end; val res = 4 : int ↑ lokal definiertes x (= 2) - x; val it = 1 : int Madjid Fathi Wissensbasierte Systeme / Wissensmanagement ←dieses x blieb unberührt Einführung in die Informatik II 49 7.5.3 Typen und Polymorphismus In funktionalen Sprachen: Typsystem hat hohen Stellenwert Strenge Typisierung: jeder Wert hat einen eindeutigen Typ in imperativen Sprachen meist abgeschwächte Typsysteme, die Uminterpretierung von Typen erlauben, z.B. durch: Typkonversion generische Typen wie void * in C oder Object in Java, um generische Funktionen zu realisieren In funktionalen Sprachen stattdessen flexible Typsysteme Typen von Variablen (inkl. Funktionen) können oft automatisch ermittelt werden: Typinferenz Konzepte wie generische Funktionen sind sinnvoll in das Typsystem integriert: Typpolymorphismus Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 50 7.5.3 Typen und Polymorphismus ... Eigenschaften des SML Typsystems Der Typ eines Ausdrucks kann allein aus der syntaktischen Struktur ermittelt werden statische Typprüfung zur Übersetzungszeit keine Laufzeit-Typfehler möglich (vgl. Java!) schnellerer und sichererer Code Das Typsystem unterstützt polymorphe Typen Typen können freie Variablen (z.B. ‘a) enthalten Funktionen können für eine ganze Klasse von Typen definiert werden dies erhöht die Wiederverwendbarkeit der Software Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 51 7.5.3 Typen und Polymorphismus ... Typausdrücke Das Typsystem in SML bildet eine eigene Sprache mit Ausdrüucken, die auch an Variable gebunden werden können Die Konstanten sind die einfachen Typen: unit, bool, int, real, char, string Operationen (Typkonstruktoren): Tupel, Records, Listen, Funktionstypen, z.B. int * int z.B. {a:int, b:string} z.B. real list z.B. string -> int Binden an Variable: type <Variable> = <Typausdruck> Beispiel: type point = real * real Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 52 7.5.3 Typen und Polymorphismus ... Parametrischer Polymorphismus Abstraktionsmechanismus für Typausdrücke: durch Variablen in Typausdrücken kann man Typen mit gegebener Struktur beschreiben Beispiele: int * string, bool * real etc. sind alles Paare int list, real list, (int * bool) list etc. sind alles Listen In einem Typausdruck steht eine Typvariable, z.B. ’a oder ’b für einen beliebigen Typ vorgestellter Apostroph zur syntaktischen Unterscheidung Typvariablen mit zwei Apostrophen (z.B. ’’a) stehen für beliebige Typen, auf denen Gleichheit definiert ist Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 53 7.5.3 Typen und Polymorphismus ... Parametrischer Polymorphismus ) Die Menge aller Paar-Typen ist damit: ’a * ’b Menge aller Listen-Typen: ’a list Menge aller Funktionstypen, die zu einer Liste einen Wert ihres Elementtyps liefern: ’a list -> ’a Definition eines polymorphen Typs: die Bindung der Typvariablen erfolgt durch Auflisten vor dem zu definierenden Typ: type ’a idPair = ’a * ’a; type (’a,’b) pairList = (’a * ’b) list; Instanziierung eines Typs: Angabe von Werten f. Typvariablen (2,2) : int idPair; [(1,"foo"),(2,"bar")] : (int,string) pairList; Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 54 7.5.3 Typen und Polymorphismus ... Polymorphe Funktionen Parametrischer Polymorphismus erlaubt die typsichere Definition generischer Funktionen Beispiel: erstes Element eines Tupels - fun first (a,b) = a; val first = fn : ’a * ’b -> ’a Beispiel: Länge einer Liste - fun length l = if l=[] then 0 else 1 + length(tl l); val length = fn : ’’a list -> int Argument vom Typ ’’a list, da der Vergleich zweier Listen auf dem Vergleich der Elemente basiert - fun length [] = 0 = | length (hd::tl) = 1 + length(tl); val length = fn : ’a list -> int Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 55 7.5.3 Typen und Polymorphismus ... Typinferenz: Wie bestimmt man den Typ eines Ausdrucks? Beispiel: fun f (x,y) = x + 1 = y; Starte mit dem allgemeinsten möglichen Typ für jedes Element des Ausdrucks: type(x) = ’a, type(y) = ’b, type(1) = int, type(f) = ’c -> ’d Füge Gleichungen hinzu, die sich aus der Struktur des Ausdrucks ergeben und löse das Gleichungssystem: aus x+1 folgt ’a = type(1) und type(x+1) = ’a aus x+1=y folgt ’b = type(x+1) und type(x+1=y) = bool aus (x,y) folgt type((x,y)) = ’a * ’b aus fun f(x,y) = x+1=y folgt: ’c = type((x,y)) und ’d = type(x+1=y) Lösung: type(f) = int * int -> bool Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 56 Klausurtermine EI2 im SS 2011 1. Termin: Mo., 08.08.2011, 10:15 - 12:15 Uhr AR/E/1-8101 - Audimax 2. Termin: Fr., 23.09.2011, 10:15 - 12:15 Uhr AR/E/2-9202/03 – Turnhalle Anmeldezeitraum für Klausuren beim Prüfungsamt Informatik: Mo., 04.07. – Fr., 15.07.2011 (2 Wochen) alle anderen: bei Frau Wenderoth (Raum H-A 8111, 10-13 Uhr) Durchführung ohne Hilfsmittel Kurzreferenz zu Java-Klassen und SML als Anlage Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 57 Zur Klausur EI2 im SS 2011 1. Termin: Mo., 08.08.2011, 10:15 - 12:15 Uhr AR/E/1-8101 - Audimax 2. Termin: Fr., 23.09.2011, 10:15 - 12:15 Uhr AR/E/2-9202/03 – Turnhalle Aufteilung des Stoffes: ca. 20% UML ca. 60% Java-Programmierung u.a. Vererbung, Exceptions, Collections, GUIs, (Threads) ca. 5-10% Entwurfsmuster ca. 10-15% SML-Programmierung u.a.Typen, Funktionen Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 58 Mögliche Fragetypen Fragestellungen: UML-Klassendiagramme (OOA / OOD) zeichnen Umsetzung von UML nach Java oder umgekehrt einfache Programmieraufgaben i.a. als Lückentext (wenige Zeilen) vorgegebene Programme verstehen Was ist die Ausgabe? Wo sind Fehler im Programm? Bei SML: Typ/Wert von Ausdrücken/Funktionen Wissensfragen zum Ankreuzen Musterklausur: siehe Duesie Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 59 7.6 Datentypen und Pattern Matching Typen, die mit type an Variablen gebunden werden, stellen lediglich abkürzende Schreibweisen dar innerer Aufbau der Datenstruktur ist offengelegt Eine SML datatype Deklaration definiert einen Typ zusammen mit seinen Konstruktoren spezifiziert wird nur, wie Werte dieses Typs erzeugt werden, nicht wie sie gespeichert oder dargestellt werden tatsächlich wird in SML nie eine Implementierung für die Konstruktoren angegeben! SML-Funktionen arbeiten lediglich auf der syntaktischen Struktur des Terms, der eine Datenstruktur erzeugt hat Berechnung basiert auf der Termalgebra Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 60 7.6 Datentypen und Pattern Matching ) Variantentypen Ein Datentyp besteht aus einer Menge typisierter Konstruktoren, von denen jeder eine Variante des Typs beschreibt Syntax für die Defninition eines Datentyps: datatype [ <Typvariablen> ] <Typname> = <Konstruktor> [ of <Typ> ] { | <Konstruktor> [ of <Typ> ] } <Typvariablen> definiert die auf der rechten Seite vorkommenden Typvariablen bei polymorphen Typen z.B. datatype ’a tree = ... <Typ> gibt den Argumenttyp des jeweiligen Konstruktors an das Ergebnis ist immer vom definierten Typ <Typname> Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 61 7.6 Datentypen und Pattern Matching ) Variantentypen ) Beispiel: Datentyp für geometrische Objekte type point = datatype geo | | real * real; = POINT of point CIRCLE of point * real RECT of {lowLeft:point, upRight:point}; (vgl. mit dem Ansatz der objektorientierten Programmierung!) Erzeugung von Werten des Datentyps geo: - val val p - val val c p = c = = POINT (1.0,2.0); POINT (1.0,2.0) : geo = CIRCLE ((2.0, 3.5), 1.0); CIRCLE ((2.0,3.5),1.0) : geo POINT (1.0,2.0) und CIRCLE ((2.0,3.5),1.0) sind Werte! sie werden als Terme bezeichnet Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 62 7.6 Datentypen und Pattern Matching ) Pattern Matching Auf die Varianten eines Datentyp-Werts kann wieder durch Pattern Matching zugegriffen werden ein Muster ist aus Konstruktoren und Variablen gebildet es passt auf einen Term derselben Struktur die Variablen im Muster werden dann an die Argumente der entsprechenden Konstruktoren im Term gebunden Beispiel: - val CIRCLE (m,r) = c; ←c wie auf voriger Folie gebunden stdIn:26.5-26.21 Warning: binding not exhaustive CIRCLE (m,r) = ... val m = (2.0,3.5) : real * real val r = 1.0 : real Warnung, da Muster nicht alle Varianten von geo abdeckt Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 63 7.6 Datentypen und Pattern Matching ) Pattern Matching: Beispiel Berechnung des Flächeninhalts eines geometrischen Objekts: - fun area (POINT _) = 0.0 = | area (CIRCLE (_,r)) = 3.1415926 * r * r = | area (RECT {lowLeft=(x1,y1),upRight=(x2,y2)}) = = abs ((x1-x2)*(y1-y2)); val area = fn : geo -> real - area (CIRCLE((0.0,0.0),1.0)); val it = 3.1415926 : real In Mustern kann anstelle einer Variable ein Unterstrich ( _ ) als anonyme Variable (wildcard) auftreten für diese ”Variable“ wird keine Bindung erzeugt Funktionsdefinitionen verlaufen mit Hilfe von Mustern ”entlang“ der Definition der Datentypen Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 64 7.6 Datentypen und Pattern Matching ) Rekursive Datentypen Bei der Definition der Varianten darf auch der gerade definierte Datentyp selbst verwendet werden dies führt zu rekursiven Typdefinitionen und damit zu rekursiven Datenstrukturen Beispiel: ein binärer Baum ganzer Zahlen datatype tree = EMPTY | NODE of int * tree * tree; Der Term NODE(3,NODE(8,EMPTY,EMPTY), NODE(1,NODE(4,EMPTY,EMPTY), EMPTY)) entspricht dann dem rechts stehenden Baum Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 65 7.6 Datentypen und Pattern Matching ) Bäume als polymorphe Datentypen Die Knoten eines Binärbaums können im Prinzip beliebige Daten enthalten Modellierung in SML durch einen polymorphen Datentyp: - datatype ’a tree = EMPTY = | NODE of ’a * ’a tree * ’a tree; datatype ’a tree = EMPTY | NODE of ’a * ’a tree * ’a tree - val t1 = NODE(3,EMPTY,EMPTY); val t1 = NODE (3,EMPTY,EMPTY) : int tree - val t2 = NODE("Hallo",EMPTY,EMPTY); val t2 = NODE ("Hallo",EMPTY,EMPTY) : string tree Damit können auch generische, polymorphe Funktionen für Bäume definiert werden Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 66 7.6 Datentypen und Pattern Matching ) Einige generische Funktionen auf Bäumen Anzahl der Knoten eines Baums: - fun nodes EMPTY = 0 = | nodes (NODE(_,l,r)) = 1 + nodes l + nodes r; val nodes = fn : ’a tree -> int - nodes EMPTY; val it = 0 : int - (* Baum von Folie 65 *) - val baum = NODE(3,NODE(8,EMPTY,EMPTY), = NODE(1,NODE(4,EMPTY,EMPTY),EMPTY)); val baum = NODE (3,NODE (8,EMPTY,EMPTY),NODE (1,NODE #, EMPTY)) : int tree - nodes baum; val it = 4 : int Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 67 7.6 Datentypen und Pattern Matching ) Einige generische Funktionen auf Bäumen ) Beispiel zur Auswertung der Funktion nodes: ⇒ ⇒ ⇒ ⇒ ⇒ nodes (NODE(3,NODE(8,EMPTY,EMPTY),EMPTY)) 1 + nodes (NODE(8,EMPTY,EMPTY)) + nodes EMPTY 1 + (1 + nodes EMPTY + nodes EMPTY) + 0 1 + (1 + 0 + 0) + 0 1 + (1 + 0) + 0 ⇒ 1 + 1 + 0 ⇒ 2 + 0 2 (Die jeweils ausgewerteten Funktionen sind blau unterstichen) Die Auswertung erfolgt durch Einsetzen der Werte für Argumente, Variablen und Funktionen eingebaute Funktionen (wie + ) werden direkt ausgewertet Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 68 7.6 Datentypen und Pattern Matching ) Einige generische Funktionen auf Bäumen ) Höhe eines Baums: - fun height EMPTY = 0 = | height (NODE(_,l,r)) = = let = val hl = height l; = val hr = height r; = in = 1 + (if hl>hr then hl else hr) = end; val height = fn : ’a tree -> int der bedingte Ausdruck berechnet das Maximum der Höhen von linkem und rechtem Unterbaum der let-Ausdruck verhindert deren doppelte Berechnung Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 69 7.6 Datentypen und Pattern Matching ) Einige generische Funktionen auf Bäumen ) Umwandlung eines Baums in eine Liste: - fun inorder EMPTY = [] = | inorder (NODE(v,l,r)) = = @ = @ val inorder = fn : ’a tree -> inorder l [v] inorder r; ’a list - inorder baum; val it = [8,3,4,1] : int list list [8,3,4,1] es wird immer erst der linke Unterbaum bearbeitet, dann der aktuelle Knoten, dann der rechte Unterbaum Inorder-Durchlauf durch den Baum Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 70 7.7 Funktionen höherer Ordnung Bisher haben wir Funktionen nur auf Datenwerte angewendet Funktionen höherer Ordnung sind Funktionen, die andere Funktionen als Argument haben oder Funktionen als Ergebnis liefern Sie sind daran erkennbar, daß ihr Typ mindestens zweimal den Typkonstruktor -> enthält Viele Operationen lassen sich mit Funktionen höherer Ordnung elegant und allgemein formulieren Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 71 7.7 Funktionen höherer Ordnung ) Beispiel: Filtern einer Liste Programmiere eine Funktion, die aus einer Liste alle Elemente ausfiltert, die eine bestimmte Bedingung erfüllen die Bedingung wird der Funktion als Argument übergeben - fun filter (p,[]) = [] = | filter (p,x::l) = if p x = then x :: filter (p,l) = else filter (p,l); val filter = fn : (’a -> bool) * ’a list -> ’a list - val l = [1,2,3,4,5,6,7,8]; val l = [1,2,3,4,5,6,7,8] : int list ← gerade Elemente - filter (fn x => x mod 2 = 0, l); val it = [2,4,6,8] : int list - filter (fn x => x > 4, l); ← Elemente > 4 val it = [5,6,7,8] : int list Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 72 7.7 Funktionen höherer Ordnung ) Currying Funktionen mit mehreren Argumenten haben wir bisher immer als Funktionen auf einem Tupel aufgefaßt: - fun mult (a,b) = a * b; val mult = fn : int * int -> int - mult (2,3); val it = 6 : int Wir können eine solche Funktion aber auch anders realisieren: die Funktion hat nur ein Argument sie liefert aber als Ergebnis eine Funktion, die auf das zweite Argument angewendet werden kann Der Aufruf sähe dann so aus: - mult 2 3; ←Ergebnis von mult 2 ist eine Funktion! val it = 6 : int Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 73 7.7 Funktionen höherer Ordnung ) Currying ) Die Umwandlung einer Funktion mehrerer Argumente in mehrere Funktionen mit einem Argument heißt Currying nach dem Logiker Haskell B. Curry Mathematisch: Currying verwandelt eine Funktion des Typs (A1 × A2 × ... × An) → B in eine Funktion des Typs A1 → A2 → ... → An → B d.h. die Anwendung dieser Funktion auf ein a1 ∈ A1 liefert eine Funktion aus A2 → ... → An → B Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 74 7.7 Funktionen höherer Ordnung ) Currying ) Wie kann eine solche Funktion in SML definiert werden? Anwendung des bisher Gelernten: die Funktion, die ihr Argument mit einem Wert x multipliziert, ist fn y => x * y das x ist dabei eine freie Variable, deren Wert durch die Umgebung bestimmt wird also können wir schreiben: - fun mult x = fn y => x * y; val mult = fn : int -> int -> int - mult 2 3; ← = (mult 2) 3 = (fn y => 2 * y) 3 val it = 6 : int Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 75 7.7 Funktionen höherer Ordnung ) Kurzschreibweise für curried Funktionen Statt fun <Variable> <Muster1> = fn <Muster2> => ... => fn <Mustern> => <Ausdruck> kann man auch kürzer schreiben: fun <Variable> <Muster1> ... <Mustern> = <Ausdruck> Eine Variable darf dabei immer nur in einem Muster auftreten Beispiele: - fun mult x y = x * y; val mult = fn : int -> int -> int - fun und false _ = false = | und _ false = false; = | und true true = true; val und = fn : bool -> bool -> bool Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 76 7.7 Funktionen höherer Ordnung ) Bedeutung des Currying Currying ermöglicht die partielle Applikation von Funktionen d.h. durch Fixierung eines Arguments erhält man eine neue Funktion, die bereits teilweise ausgewertet ist Beispiel: Summe von Funktionswerten f(1) + ... + f(n) - fun sumf 1 f = f 1 = | sumf n f = sumf (n-1) f + f n; val sumf = fn : int -> (int -> int) -> int ← = 1 + 4 + 9 + 16 + 25 - sumf 5 (fn x => x * x); val it = 55 : int - val sum2f = sumf 2; ← = fn f => f(1) + f(2) val sum2f = fn : (int -> int) -> int - sum2f (fn x => x); ← = 1 + 2 val it = 3 : int Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 77 7.7 Funktionen höherer Ordnung ) Bedeutung des Currying ) Auswertung des Ausdrucks sumf 2: ausführliche Definition der Funktion sumf ist: fun sumf 1 = (fn f => f 1) | sumf n = (fn f => sumf (n-1) f + f n); damit wird sumf 2 wie folgt ausgewertet: sumf 2 ⇒ ⇒fn f => sumf (2-1) f + f 2 ⇒ ⇒fn f => sumf 1 f + f 2 ⇒fn f => (fn f => f 1) f + f 2 ⇒fn f => f 1 + f 2 Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 78 7.7 Funktionen höherer Ordnung ) Oft genutzte Funktionen höherer Ordnung Filtern einer Liste (curried Version): - fun filter p [] = [] = | filter p (x::l) = if p x = then x :: filter p l = else filter p l; val filter = fn : (’a -> bool) -> ’a list -> ’a list Anwendung einer Funktion auf alle Elemente einer Liste: - fun map f [] = [] = | map f (x::l) = f x :: map f l; val map = fn : (’a -> ’b) -> ’a list -> ’b list - map (fn x => x*x) [1,2,3,4]; ← quadriere die Elemente val it = [1,4,9,16] : int list Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 79 7.7 Funktionen höherer Ordnung ) Oft genutzte Funktionen höherer Ordnung ) Reduzieren einer Liste mit einer binären Operation z.B. Reduktion von [1,2,3] mit + liefert 1+2+3 - fun foldr f u [] = u = | foldr f u (x::l) = f (x, foldr f u l); val foldr = fn : (’a * ’b -> ’b) -> ’b -> ’a list -> ’b foldr reduziert die Liste von rechts, d.h. die Funktion f wird rechtsassoziativ angewandt der Aufruf foldr op+ 0 [1,2,3] berechnet daher exakt op+(1, op+(2, op+(3, 0))) = 1 + ( 2 + ( 3 + 0)) Anmerkung: op erlaubt es einen Infix-Operator als Funktion (in Präfix-Notation) zu verwenden, z.B. op+ (2,3) op- ? Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 80 7.7 Funktionen höherer Ordnung ) Oft genutzte Funktionen höherer Ordnung ) Funktionskomposition o - infix 3 o; ←Infixschreibweise, Priorität 3 infix 3 o - fun (f o g) x = f(g(x)); val o = fn : (’a -> ’b) * (’c -> ’a) -> ’c -> ’b Anmerkung: die Funktionen map, foldr und o sind in SML/NJ standardmäßig definiert Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 81 7.7 Funktionen höherer Ordnung ) Beispiele zur Anwendung der Funktionen Berechne die Länge für jeden String in einer Liste: - map size ["Dies","ist","ein","Satz"]; val it = [4,3,3,4] : int list Berechne die Summe über eine Liste ganzer Zahlen: - val sum = foldr op+ 0; ←rechte Seite ist Funktion! val sum = fn : int list -> int - sum [1,2,3,4]; val it = 10 : int Gesamtlänge aller Strings in einer Liste: - val gsum = sum o (map size); val gsum = fn : string list -> int - gsum ["Dies","ist","ein","Satz"]; val it = 14 : int Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 82 7.7 Funktionen höherer Ordnung ) Beispiele zur Anwendung der Funktionen ) Listenkonkatenation: fun l1 @ l2 = foldr op:: l2 l1 z.B.: [1,2]@[3] = foldr op:: [3] [1,2] = 1::(2::[3]) Listenlänge: fun length l = foldr (fn (x,y) => y+1) 0 l wenn wir fn (x,y) => y+1 einmal abkürzend mit f bezeichnen, wird z.B. length [6,7,8] wie folgt berechnet: f(6,f(7,f(8,0))) = f(6,f(7,1)) = f(6,2) = 3 Letztes Listenelement: val last = hd o rev d.h. last l = hd (rev l) String-Umkehr: val revert = implode o rev o explode d.h. revert s = implode(rev(explode s)) Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 83 7.8 Problemlösung mit Rekursion 7.8.1 Die Türme von Hanoi Gegeben ist ein Turm von Holzscheiben: Der Turm ist vom linken auf den rechten Stab zu verschieben, wobei immer nur jeweils eine Scheibe bewegt werden und nie eine größere auf einer kleineren Scheibe liegen darf Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 84 7.8.1 Die Türme von Hanoi ) Lösung des Problems: Ausgangssituation: 0 Madjid Fathi Wissensbassierte Systeme / Wissensmanagement 1 2 Einführung in die Informatik II 85 7.8.1 Die Türme von Hanoi ) Lösung des Problems: ) Schiebe die oberen n-1 Scheiben von Pos. 0 auf Pos. 1: 0 Madjid Fathi Wissensbassierte Systeme / Wissensmanagement 1 2 Einführung in die Informatik II 86 7.8.1 Die Türme von Hanoi ) Lösung des Problems: ) Schiebe die unterste Scheibe von Pos. 0 auf Pos. 2: 0 Madjid Fathi Wissensbassierte Systeme / Wissensmanagement 1 2 Einführung in die Informatik II 87 7.8.1 Die Türme von Hanoi ) Lösung des Problems: ) Schiebe die oberen n-1 Scheiben von Pos. 1 auf Pos. 2: 0 Madjid Fathi Wissensbassierte Systeme / Wissensmanagement 1 2 Einführung in die Informatik II 88 7.8.1 Die Türme von Hanoi ) Und wie verschieben wir einen Turm der Höhe n-1? Antwort: Genauso! (Prinzip der Rekursion!) 0 Madjid Fathi Wissensbassierte Systeme / Wissensmanagement 1 2 Einführung in die Informatik II 89 7.8.1 Die Türme von Hanoi ) Und wie verschieben wir einen Turm der Höhe n-1? ) Schiebe die obersten n-2 Scheiben von Pos. 1 auf Pos. 0 0 Madjid Fathi Wissensbassierte Systeme / Wissensmanagement 1 2 Einführung in die Informatik II 90 7.8.1 Die Türme von Hanoi ) Und wie verschieben wir einen Turm der Höhe n-1? ) Schiebe die unterste Scheibe von Pos. 1 auf Pos. 2 0 Madjid Fathi Wissensbassierte Systeme / Wissensmanagement 1 2 Einführung in die Informatik II 91 7.8.1 Die Türme von Hanoi ) Und wie verschieben wir einen Turm der Höhe n-1? ) Schiebe die obersten n-2 Scheiben von Pos. 0 auf Pos. 2 0 Madjid Fathi Wissensbassierte Systeme / Wissensmanagement 1 2 Einführung in die Informatik II 92 7.8.1 Die Türme von Hanoi ) SML-Programm für die allgemeine Lösung - (* Die folgende Spezialanweisung sorgt dafür, daß der *) - (* Compiler auch längere Listen vollständig ausgibt. *) - Control.Print.printLength := 100; val it = () : unit - fun hanoi(1,A,B,C) = [(A,C)] = | hanoi(n,A,B,C) = hanoi(n-1,A,C,B) = @ [(A,C)] = @ hanoi(n-1,B,A,C); val hanoi = fn : int * ’a * ’a * ’a -> (’a * ’a) list - hanoi(4, 0, 1, 2); val it = [(0,1),(0,2),(1,2),(0,1),(2,0),(2,1),(0,1),(0,2),(1,2), (1,0),(2,0),(1,2),(0,1),(0,2),(1,2)] : (int * int) list Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 93 7.8.1 Die Türme von Hanoi ) Visualisierung der Lösung für Turmhöhe 4 Schritt 1: Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 94 7.8.1 Die Türme von Hanoi ) Visualisierung der Lösung für Turmhöhe 4 Schritt 2: Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 95 7.8.1 Die Türme von Hanoi ) Visualisierung der Lösung für Turmhöhe 4 Schritt 3: Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 96 7.8.1 Die Türme von Hanoi ) Visualisierung der Lösung für Turmhöhe 4 Schritt 4: Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 97 7.8.1 Die Türme von Hanoi ) Visualisierung der Lösung für Turmhöhe 4 Schritt 5: Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 98 7.8.1 Die Türme von Hanoi ) Visualisierung der Lösung für Turmhöhe 4 Schritt 6: Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 99 7.8.1 Die Türme von Hanoi ) Visualisierung der Lösung für Turmhöhe 4 Schritt 7: Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 100 7.8.1 Die Türme von Hanoi ) Visualisierung der Lösung für Turmhöhe 4 Schritt 8: Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 101 7.8.1 Die Türme von Hanoi ) Visualisierung der Lösung für Turmhöhe 4 Schritt 9: Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 102 7.8.1 Die Türme von Hanoi ) Visualisierung der Lösung für Turmhöhe 4 Schritt 10: Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 103 7.8.1 Die Türme von Hanoi ) Visualisierung der Lösung für Turmhöhe 4 Schritt 11: Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 104 7.8.1 Die Türme von Hanoi ) Visualisierung der Lösung für Turmhöhe 4 Schritt 12: Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 105 7.8.1 Die Türme von Hanoi ) Visualisierung der Lösung für Turmhöhe 4 Schritt 13: Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 106 7.8.1 Die Türme von Hanoi ) Visualisierung der Lösung für Turmhöhe 4 Schritt 14: Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 107 7.8.1 Die Türme von Hanoi ) Visualisierung der Lösung für Turmhöhe 4 Schritt 15: Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 108 7.8.1 Die Türme von Hanoi ) Visualisierung der Lösung für Turmhöhe 4 Schritt 16: Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 109 7.8.1 Die Türme von Hanoi ) Wie lösen wir ein Problem durch Rekursion? Wir gehen davon aus, daß alle kleineren Probleme bereits gelöst sind Dann konstruieren wir aus der Lösung der kleineren Probleme eine Lösung des größeren Problems oft: konstruiere aus der Lösung für die Problemgröße n eine Lösung für die Problemgröße n + 1 Zu beachten ist jetzt noch der Terminierungsfall, d.h. wir brauchen noch eine Lösung für die kleinsten Probleme oft: Problemgröße 0 oder 1 Vgl. das Beweisprinzip der vollständigen Induktion! Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 110 7.8 Problemlösung mit Rekursion ... 7.8.2 Das Damenproblem Gegeben ist ein Schachbrett mit n * n Feldern Gesucht sind alle Stellungen für n Damen auf dem Schachbrett, so daß sich keine zwei Damen gegenseitig bedrohen d.h. keine zwei Damen in derselben Reihe, Linie oder Diagonale Beispiel für n = 8: s. rechts Offensichtlich: auf jeder Linie muß genau eine Dame stehen Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 111 7.8.2 Das Damenproblem ... Rekursiver Lösungsansatz Verallgemeinerung: wir betrachten auch nicht-quadratische Schachbretter Angenommen, wir haben bereits die Lösung L für ein Brett der Größe n * (m− 1) d.h. alle möglichen Stellungen der (m− 1) Damen Wir erhalten dann die Lösungen für ein n * m Brett wie folgt: bilde neue Stellungskandidaten: kombiniere alle Stellungen aus L mit jeder möglichen Position der Dame auf der neuen Linie behalte davon die Stellungen, die ”sicher“ sind Rekursionsende beim n * 0 Brett: Lösungsmenge ist leer ... Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 112 7.8.2 Das Damenproblem ... Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 113 7.8.2 Das Damenproblem ... Darstellung der Daten Eine Position ist ein Paar ganzer Zahlen (Reihe, Linie) Datentyp (int * int) Eine Stellung ist eine Liste mit den Positionen aller Damen Datentyp (int * int) list Die Lösung ist eine Liste von Stellungen Datentyp (int * int) list list Ein Stellungskandidat ist ein Paar: ( Position der neuen Dame, Stellung für n * (m − 1) Brett ) Datentyp (int * int) * (int * int) list nach dem Ausfiltern der sicheren Stellungen reihen wir das erste Element dieses Paars in die Stellungs-Liste ein Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 114 7.8.2 Das Damenproblem ... Erzeugung der Stellungskandidaten Die Liste der Stellungskandidaten ist das kartesische Produkt aus: Liste der möglichen Positionen der m-ten Dame Liste der Stellungen für das n * (m− 1) Brett Kartesisches Produkt zweier Listen: [a1, ..., an] × [b1, ..., bm] = [ (a1, b1), ... , (a1, bm), (a2, b1), ... , (a2, bm), ... ... (an, b1), ... , (an, bm)] Hilfsfunktion dafür: Produkt eines Skalars mit einer Liste: a · [b1, ..., bm] = [(a, b1), ... , (a, bm)] Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 115 7.8.2 Das Damenproblem ... Erzeugung der Stellungskandidaten ) SML-Funktion für das Produkt eines Skalars mit einer Liste: - fun prod x [] = [] = | prod x (hd::tl) = (x, hd) :: (prod x tl); val prod = fn : ’a -> ’b list -> (’a * ’b) list - prod 8 [1,2,3,4]; val it = [(8,1),(8,2),(8,3),(8,4)] : (int * int) list SML-Funktion für das kartesische Produkt zweier Listen: - fun cartesian [] l = [] = | cartesian (hd::tl) l = (prod hd l) = @ (cartesian tl l); val cartesian = fn : ’a list -> ’b list -> (’a * ’b) list - cartesian [1,2] [3,4]; val it = [(1,3),(1,4),(2,3),(2,4)] : (int * int) list Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 116 7.8.2 Das Damenproblem ... Weitere Hilfsfunktionen für die Lösung Eine Funktion, die die Liste [1,2,...,n] erzeugt - fun enumerate 0 = [] = | enumerate n = enumerate(n-1) @ [n]; val enumerate = fn : int -> int list - enumerate 8; val it = [1,2,3,4,5,6,7,8] : int list Damit: Liste der möglichen Positionen für die neue Dame - cartesian (enumerate 8) [5]; val it = [(1,5),(2,5),(3,5),(4,5),(5,5),(6,5),(7,5), (8,5)] : (int * int) list hier: 5-te Dame auf dem 8 * 8 Brett Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 117 7.8.2 Das Damenproblem ... Wann ist eine Stellung sicher? Hilfsfunktion: kann eine Dame auf Feld (i, j) die Dame auf Feld (k, l) schlagen? - fun capture (i,j) (k,l) = i = k orelse j = l = orelse (i-j) = (k-l) = orelse (i+j) = (k+l); val capture = fn : int * int -> int * int -> bool Prädikat: Dame auf Feld p ist zusammen mit gegebener Stellung der anderen Damen sicher - fun safe (p,[]) = true = | safe (p,hd::tl) = not (capture p hd) = andalso safe (p,tl); val safe = fn : (int * int) * (int * int) list -> bool Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 118 7.8.2 Das Damenproblem ... Herausfiltern der sicheren Stellungen Anwendung der Funktion filter: - filter safe [((1,3),[(1,2),(3,1)]), = ((1,3),[(3,2),(5,1)])]; val it = [((1,3),[(3,2),(5,1)])] : ((int * int) * (int * int) list) list das Argument ist eine Liste von Stellungskandidaten Umwandlung des Ergebnisses in eine Liste von Stellungen: - map (fn (x,l) => x::l) [((1,3),[(3,2),(5,1)])]; val it = [[(1,3),(3,2),(5,1)]] : (int * int) list list aus jedem Paar (x, [y1, ..., yn]) in der Liste wird eine Liste [x, y1, ..., yn] Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 119 7.8.2 Das Damenproblem ... Berechnung aller Lösungen Erzeuge alle Lösungen für ein n * m Brett: - fun allValidBoards n 0 = [[]] = | allValidBoards n m = = map (fn (x,l) => x::l) ( = filter safe ( = cartesian (cartesian (enumerate n) [m]) = (allValidBoards n (m-1)) = ) = ); val allValidBoards = fn : int -> int -> (int * int) list list Erzeuge alle Lösungen für ein n * n Brett: - fun queens n = allValidBoards n n; val queens = fn : int -> (int * int) list list Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 120 7.8.2 Das Damenproblem ... Berechnung aller Lösungen ... Beispiel: 4 * 4 Brett - queens 4; val it = [[(2,4),(4,3),(1,2),(3,1)],[(3,4),(1,3), (4,2),(2,1)]] : (int * int) list list Anzahl der Lösungen für n = 1, ..., 10: - map (fn n => length (queens n)) (enumerate 10); val it = [1,0,0,2,10,4,40,92,352,724] : int list Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 121 7.8 Problemlösung mit Rekursion ... 7.8.3 Symbolisches Differenzieren Funktionale Sprachen sind gut geeignet zur symbolischen Manipulation von Termen Einfaches Beispiel: Differenzieren von Funktionen Mathematische Regeln: Beispiel: Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 122 7.8.3 Symbolisches Differenzieren ... Eine Datenstruktur für Terme Rekursive Datenstruktur mit Konstruktoren für: Konstante und Variablen Addition und Multiplikation Keine Klammern in der Datenstruktur, da die Struktur des Terms durch die Verschachtelung der Konstruktoren gegeben ist Definition des Datentyps in SML: - datatype term = CONST of int | VAR of string = | ADD of term * term = | MUL of term * term; Anmerkung: eigentlich sollte es CONST of real heißen SML/NJ hat (wegen des fehlenden Gleichheitsoperators) aber Probleme beim Pattern Matching mit real-Werten Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 123 7.8.3 Symbolisches Differenzieren ... Eine Datenstruktur für Terme ) Beispiel: Term für x2 + y + 2 - val t = ADD(ADD(MUL(VAR "x", VAR "x"), VAR "y"), = CONST 2); val t = ADD (ADD (MUL #,VAR #),CONST 2) : term Ausgabe nur bis zu einer festen Tiefe (einstellbar) Baumstruktur des Terms: Anmerkung: statt ADD / MUL wären auch Infix-Operatoren möglich Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 124 7.8.3 Symbolisches Differenzieren ... Eine Funktion zum symbolischen Differenzieren - fun deriv = | deriv = = | deriv = | deriv = val deriv = (CONST _) x = CONST 0 (VAR v) x = if x = v then CONST 1 else CONST 0 (ADD (t1,t2)) x = ADD (deriv t1 x, deriv t2 x) (MUL (t1,t2)) x = ADD (MUL(deriv t1 x, t2), MUL(t1, deriv t2 x)); fn : term -> string -> term Rekursion über die Struktur des Terms dabei Pattern Matching zur musterbasierten Transformation der Baumstruktur Typisch für Algorithmen auf rekursiven Strukturen Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 125 7.8.3 Symbolisches Differenzieren ... Eine Funktion zum symbolischen Differenzieren ) Beispiele zur Anwendung der Funktion: Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 126 7.8.3 Symbolisches Differenzieren ... Eine Funktion zum Vereinfachen Die berechneten Terme sollten am Ende noch vereinfacht werden also z.B. 2 · x statt 1 · x + x · 1 + 0 + 0 Realisierbar durch rekursive Funktion mit Pattern Matching, z.B.: - fun simpl (ADD (t, CONST 0)) = simpl t ←t + 0 = t = | simpl (ADD (CONST 0, t)) = simpl t ←0 + t = t = | simpl (MUL (t, CONST 1)) = simpl t ←t · 1 = t = | simpl (MUL (CONST 1, t)) = simpl t ←1 · t = t = | simpl (MUL (_, CONST 0)) = CONST 0 ←t · 0 = 0 = | simpl (MUL (CONST 0, _)) = CONST 0 ←0 · t = 0 = | simpl (ADD (t1, t2)) = ←t+t = 2·t = if t1=t2 then MUL (CONST 2, simpl t1) = else ADD (simpl t1, simpl t2) = | simpl (MUL (t1, t2)) = MUL (simpl t1, simpl t2) = | simpl t = t; Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 127 7.8.3 Symbolisches Differenzieren ... Eine Funktion zum Vereinfachen ) Beispiele: - simpl tx; val it = ADD (VAR "x",VAR "x") : term - simpl it; val it = MUL (CONST 2,VAR "x") : term - simpl (simpl (simpl ty)); val it = CONST 1 : term Die Funktion könnte noch so erweitert werden, daß sie solange vereinfacht, bis sich der Term nicht mehr ändert ... Anmerkung: mit CONST of real würde das Muster fun simpl (ADD (t, CONST 0.0)) = ... in SML/NJ zu einem Syntaxfehler führen Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 128 7.9 Auswertung funktionaler Programme Eifrige Auswertung (Eager Evaluation) Auswertung von Ausdrücken in SML ist Folge von Ersetzungen Variablen werden durch den Wert ersetzt, an den sie in der aktuellen Umgebung gebunden sind Argumente von Funktionen werden ausgewertet und die Werte in die Funktionsdefinition eingesetzt Beispiel: betrachte fun sqr x = x * x; Auswertung von sqr(sqr(sqr 2): sqr(sqr(sqr 2) ⇒sqr(sqr(2 * 2)) ⇒sqr(sqr 4) ⇒ sqr(4 * 4)) ⇒sqr 16 ⇒ 16 * 16 ⇒ 256 Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 129 7.9 Auswertung funktionaler Programme ) Eifrige Auswertung (Eager Evaluation) Bei der eifrigen Auswertung werden die Argumente einer Funktion immer vollständig ausgewertet, bevor der definierende Funktionsausdruck ausgewertet wird die Funktion erhält die Werte der Argumente (Call by value) Folge: hat ein Argument einen undefinierten Wert, so hat die Funktionsanwendung ebenfalls einen undefinierten Wert Beispiele: sqr (1 div 0); sqr (fak ~1); ←1 div 0 ist undefiniert und damit auch sqr (1 div 0) ←fak ~1 terminiert nicht und damit auch sqr (fak ~1) Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 130 7.9 Auswertung funktionaler Programme ) Strikte Funktionen Eine Funktion Argument, wenn gilt: heißt strikt im k-ten hat nur dann einen definierten Wert, wenn auch ek einen definierten Wert hat Oder umgekehrt: ist undefiniert, so auch In SML sind (fast) alle Funktionen strikt in allen Argumenten einzige Ausnahmen: andalso: nicht strikt im 2. Argument orelse: nicht strikt im 2. Argument if then else: nicht strikt im 2. und 3. Argument Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 131 7.9 Auswertung funktionaler Programme ) Verzögerte Auswertung (Lazy Evaluation) Argumente, in denen eine Funktion nicht strikt ist, dürfen erst dann ausgewertet werden, wenn es wirklich notwendig ist verzögerte Auswertung Beispiel: Zweierpotenz fun even n = (n mod 2 = 0); fun ZP n = n=1 orelse (even(n) andalso ZP(n div 2)); Auswertung von ZP(7): ZP(7) ⇒7=1 orelse (even(7) andalso ZP(7 div 2)) ⇒false orelse (even(7) andalso ZP(7 div 2)) ⇒even(7) andalso ZP(7 div 2) ⇒ ... ⇒false andalso ZP(7 div 2) ⇒false Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 132 7.9 Auswertung funktionaler Programme ) Verzögerte Auswertung (Lazy Evaluation) ) Im Beispiel wurden orelse und andalso ausgewertet, bevor ihr 2. Argument ausgewertet wurde Der Funktion wird also statt des Werts des Arguments der definierenden Ausdruck übergeben diese Art der Parameterübergabe heißt Call by name Beispiel: Auswertung von sqr(sqr(sqr 2)) mit Call by name: sqr(sqr(sqr 2)) ⇒ sqr(sqr 2) * sqr(sqr 2) ⇒(sqr 2 * sqr 2) * (sqr 2 * sqr 2) ⇒((2 * 2) * (2 * 2)) * ((2 * 2) * (2 * 2)) ⇒... ⇒ 256 Problem: mehrfache Auswertung desselben Ausdrucks Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 133 7.9 Auswertung funktionaler Programme ) Verzögerte Auswertung (Lazy Evaluation) ) Call by need ist wie Call by name, stellt aber sicher, daß jeder Ausdruck höchstens einmal ausgewertet wird Anwendung in vielen funktionalen Sprachen (nicht bei SML!) Motivationen für verzögerte Auswertung: Realisierung nicht strikter Funktionen, z.B.: fun f (x,y) = if x=0 then y else x; f (3, 1 div 0); ←der Wert sollte 3 sein ... Einsparung überflüssiger Berechnungen, z.B.: bestimme eine Lösung des 8-Damenproblems: hd (queens 8); ohne auch die anderen 91 Lösungen zu berechnen ... Realisierung unendlicher Datenstrukturen Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 134 7.9 Auswertung funktionaler Programme ) Verzögerte Auswertung in SML In SML kann verzögerte Auswertung realisiert werden, wenn man Argumente nicht direkt übergibt, sondern in Funktionen verpackt Im Beispiel der vorigen Folie: - fun f (x,y) = if x=0 then y() else x; val f = fn : int * (unit -> int) -> int - f(3, fn () => 1 div 0); val it = 3 : int an y wird hier kein int-Wert übergeben, sondern eine Funktion, die beim Aufruf (d.h. erst bei Bedarf) den int-Wert liefert die Funktion ist vom Typ unit -> int, hat also immer () als Argument Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 135 7.9 Auswertung funktionaler Programme ) Unendliche Listen in SML Mit verzögerter Auswertung lassen sich auch unendliche Datenstrukturen erzeugen und bearbeiten Beispiel: unendliche Liste (Stream, Sequenz) type ’a lazy = unit -> ’a; datatype ’a sequ = NIL | CONS of ’a * ’a sequ lazy; der Rest der Sequenz ist durch eine Funktion beschrieben, die diese Restsequenz erzeugt Die Liste aller natürlichen Zahlen: - fun from val from = - val nats val nats = n = CONS(n, fn () => from (n+1)); fn : int -> int sequ = from 1; CONS (1,fn) : int sequ Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 136 7.9 Auswertung funktionaler Programme ) Unendliche Listen in SML ) Funktionen für das erste Element und den Reststrom: - fun head (CONS(x,_)) = x; val head = fn : ’a sequ -> ’a - fun tail NIL = NIL = | tail (CONS(_,r)) = r(); val tail = fn : ’a sequ -> ’a sequ - head(tail(tail nats)); ←drittes Element von nats val it = 3 : int Auch alle anderen Listenfunktionen lassen sich analog für Sequenzen realisieren neue, mächtige Datenstruktur ... Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 137 7.10 SML: Zusammenfassung Die Ausdrucksfähigkeit von SML wird bewirkt durch: Integrierte ”Collections“: Tupel, Records, Listen Betrachtung von Funktionen als normale Werte damit: Funktionen höherer Ordnung, Currying Automatische Bestimmung der Typen (Typinferenz) Polymorphes Typsystem (parametrisierte Typen) damit: typsichere generische Funktionen Konstruktorbasierte Datentypen Pattern Matching von Funktionsargumenten Rekursion (Funktionen und Datentypen) Madjid Fathi Wissensbassierte Systeme / Wissensmanagement Einführung in die Informatik II 138