Haskell und Python Haskell: Eine funktionale Programmiersprache funktional, nicht-strikt, hat ein polymorphes und starkes Typsystem, flexible Datenstrukturen, gute Abstraktionseigenschaften, Ziele: pures Programmieren, Auswerten von Ausdrücken rekursives Programmieren, Typsystem Python: Eine prozedurale Programmiersprache prozedural; schwaches, dynamisches Typsystem, flexible Datenstrukturen, Objektorientierung. Ziele: Demonstration imperativer und prozeduraler Konzepte, Vergleich von Konzepten P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 1 Interpreter / Compiler Interpreter Compiler (Übersetzer) Ablaufumgebung führt ein Programm aus, (bzw. wertet ein Programm aus), Grundlage: Text des Programms Jeder Programmbefehl wird einzeln eingelesen und dann ausgeführt. erzeugt aus Programm einen ausführbaren Modul. Programmumstellungen, Optimierungen Effekt des Programms muss gleich bleiben. Hier erfolgt die Ausführung des Moduls Es gibt Zwischenformen P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 2 Laufzeit / Compilezeit Compilezeit: Zeitraum der Analyse bzw. Übersetzung des Programms statische Typüberprüfung, Optimierung. Laufzeit: Zeitraum der Ausführung des Programms Z.B. dynamische Typüberprüfung, Ein-Ausgabe. P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 3 Programmiersprachen: wesentliche Merkmale imperativ Programm ist Folge von Befehlen sukzessive Änderung des Speicherinhalts Ergebnis: letzter Zustand Ein imperatives Programm sagt präzise: was (welche Anweisung), wann (Reihenfolge der Anweisungen) womit (Speicherplatz/Variable) zu geschehen hat. prozedural: Strukturierung in (imperativen) Programmiersprachen Prozedur = Unterprogramm Aufruf mit Argumenten im Programm Ziel: Übersichtlichkeit; Wiederverwendbarkeit P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 4 Programmiersprachen: Merkmale (2) funktional: Programm strukturiert in Funktionsdefinitionen Ausdrücke = Anwendung von Funktionen auf Argumente Berechnung = Auswertung von Ausdrücken Varianten von funktionalen Programmiersprachen: nicht-strikt: Argumente werden so spät wie möglich ausgewertet strikt: Argumente werden vor Funktionsaufruf ausgewertet pur: Objekte haben nur einen Wert, keine Mutation nicht-pur: Objekte können verändert werden, Seiteneffekte möglich deklarativ: Idealfall: Spezifikation = deklaratives Programm Betonung auf Logik, weniger algorithmisch Beispiele: logische Programmierung, Prolog P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 5 Programmiersprachen: Merkmale (3) objektorientiert: Verwendung in imperativen Programmiersprachen Strukturierung des Programm in Klassen. Ziel: Übersichtlichkeit, Wiederverwendung Ausführung eines Programms: Erzeugung von Objekten Austausch von Nachrichten zwischen Objekten typisiert Alle Programmiersprachen haben Typisierung • statische Typisierung: Programmtext • dynamische Typisierung: Ausführungszeit des Programms • • schwache Typisierung: Typfehler zur Laufzeit sind möglich starke Typisierung: Typfehler zur Laufzeit sind nicht möglich P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 6 Haskell Wichtige Eigenschaften funktionaler Programmiersprachen Referentielle Transparenz Gleiche Funktion, gleiche Argumente =⇒ gleicher Wert Keine Seiteneffekte ! Verzögerte Auswertung Nur die für das Resultat notwendigen Unterausdrücke werden (so spät wie möglich) ausgewertet. Polymorphes Typsystem Nur Ausdrücke mit Typ sind erlaubt — es gibt Typvariablen. Das Typsystem garantiert: keine dynamischen Typfehler. Automatische Speicherverwaltung Anforderung und Freigabe von Speicher Funktionen sind Datenobjekte mögliche Verwendung: in Datenobjekten, als Argument, als Resultat. P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 7 Programmierung in Haskell Interpreter Hugs 98 und GHCi Grundprinzipien: • Definition von Funktionen quadrat x = x*x • Aufbau von Ausdrücken: Anwendung der Funktion auf Argumente, die wieder Ausdrücke sein können. 3*(quadrat 5) • Nur der Wert zurückgegeben. P raktische Inf ormatik 1, W S von 2004/05, F olien Haskell 1, Ausdrücken 75 (3. N ovember2004) Seite 8 wird bei der Auswertung Umgang mit dem Interpreter Aufruf: Online-Report >:h >:t Ausdruck >:set +t ... ghci (im richtigen Fenster) http://www.haskell.org/onlinereport Hilfe druckt den Typ des Ausdrucks Optionen ändern Module im Interpreter verwenden: :m +Char +Numeric ... P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 9 Einfache Daten und Operatoren • ganze Zahlen • • • • • beliebig lange ganze Zahlen rationale Zahlen Gleitkommazahlen Zeichen Datenkonstruktoren • • • Arithmetische Operatoren: Arithmetische Vergleiche: Logische Operatoren: P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Typ Int mit |n| ≤ 231 − 1 = 2147483647 (vom Typ Integer), 3%7 (Rational) 3.456e+10 (Float) ’a’ Char True, False; Typ Bool +, −, ∗, /, ==, <=, < . . . &&, ||, not Seite 10 Beispiel Definition eines Polynoms x2 + y 2: quadratsumme x y = quadrat x + quadrat y Auswertung: ... Main> quadratsumme 3 4 25 P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 11 Typen in Haskell Typ Int Integer Float Double Integer -> Integer -> Integer -> P raktische Inf ormatik 1, W S Integer -> Integer Integer -> 2004/05, F olien Haskell 1, Integer Integer (3. N ovember2004) Konstanten, Funktionen 1,2,3,4,. . . 1,2,3,4,. . . 1.23e45 1.23e45 (+) quadrat quadratsumme Seite 12 Typen in Haskell Beispiel Die Ausgabe des Interpreters für die Addition (+) ist komplizierter: (+) :: forall a. (Num a) => a -> a -> a D.h.: Für alle Typen a, die man als numerisch klassifiziert hat, d.h. die in der Typklasse Num sind, hat (+) den Typ a -> a -> a Z.B. gilt: (+)::Integer -> Integer -> Integer (+)::Double -> Double -> Double P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 13 (vereinfachte) Haskell-Syntax hFunktionsDefinitioni ::= hFunktionsnameihParameteri∗ = hAusdrucki hAusdrucki ::= hBezeichneri | hZahli | (hAusdrucki hAusdrucki) | (hAusdrucki) | (hAusdruckihBinInfixOpi hAusdrucki) hBezeichneri ::= hFunktionsnamei | hDatenkonstruktornamei | hParameteri | hBinInfixOpi hBinInfixOpi ::= ∗ | + | − | / Argumente einer Funktion: Anzahl der Argumente: P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, formale Parameter. Stelligkeit der Funktion: (ar(f )) (3. N ovember2004) Seite 14 Beispiel zur Grammatik quadratsumme x y = (quadrat x) + (quadrat y) quadratsumme x,y = (quadrat x) + (quadrat y) + quadrat x P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, Funktionsname formale Parameter gleiches Zeichen wie in Grammatik hAusdrucki der Form hAusdrucki + hAusdrucki binärer Infix-Operator Anwendung: quadrat ist ein Ausdruck und x ist ein Ausdruck (3. N ovember2004) Seite 15 Haskell: Verschiedenes . . . Prelude: vordefinierte Funktionen, Typen und Datenkonstruktoren Präfix, Infix, Prioritäten ist möglich für Operatoren Konventionen zur Klammerung: s1 s2 . . . sn ≡ ((. . . (s1 s2) s3 . . .) sn) Kontextbedingungen in Funktionsdefinitionen: formale Parameter müssen verschiedenen sein; Keine undefinierten Variablen im Rumpf! Weitere Trennzeichen: “{“,“}“ Semikolon “; “ Layout-sensibel: bewirkt Klammerung mit {, }. P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 16 Fallunterscheidung Syntax: if hAusdrucki then hAusdrucki else hAusdrucki if“, then“, else“ sind reservierte (Schlüsselworte) ” ” ” und dürfen nicht als Funktionsnamen bzw. Parameternamen verwendet werden. Der erste Ausdruck ist eine Bedingung. Diese muss Typ Bool haben. Typisierung: if Bool . . . then typ else typ (if 1 then 1 else 2) ergibt einen Fehler P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 17 Bedingungen, Arithmetische Vergleiche Die Infixoperatoren ==, <, >, <=, >=, / = haben den Typ: Integer -> Integer -> Bool Achtung: = ist reserviert für Funktionsdefinitionen, und let Boolesche Ausdrücke sind kombinierbar mit not, ||, && (nicht, oder, und) Konstanten sind True, False. Eine kompliziertere Bedingung: 3.0 <= x && x < 5.0 P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 18 Darstellungen eines Programms Benutzer-Syntax: vom Programmierer benutzt Interne Syntax: “Linearisierung“; entzuckerte Version; voll geklammert; alle Operatoren sind Präfix; kein Layout Ableitungsbaum (Herleitungsbaum): Vom Kompiler erzeugt Syntaxbaum: Eindeutige Darstellung des Programms in einem markierten Baum. Hierauf lässt sich eindeutig die Ausführung des Programms definieren. P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 19 Syntaxbaum: Beispiele if x <= 0 then 1 else x*(quadrat (x-1)) ifThenElseXXXXXXX <= FF y x yy yy y y |y y iii iiii i i i ii iiii it iii FF FF FF F" 1 XXXXXX XXXXXX XXXXXX XXXXXX X, oo o o oo ooo o o oo wooo ∗ x 0 pp ppp p p p pw pp quadrat x P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 20 app − ppp pp ppp p p pp pw pp 1 Syntaxbaum: Beispiele Zwei Syntaxbäume zu 1*2: ∗ >>> 1 >> >> > appFF tt tt t tt ty t appJJ 2 ∗ P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, FF FF FF F" (3. N ovember2004) yy yy y yy y| y Seite 21 JJJ JJJ JJJ % 1 2 Aufrufhierarchie und Rekursive Definitionen f, g, fi seien Haskell-definierte Funktionen. f referenziert g direkt, f referenziert g (indirekt), f ist direkt rekursiv, f ist rekursiv, Verschränkte Rekursion: P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, wenn g im Rumpf von f vorkommt. wenn es Funktionen f1, . . . , fn gibt, so dass gilt: f referenziert direkt f1, f1 referenziert direkt f2, . . . , fn referenziert direkt g. wenn f sich selbst direkt referenziert. wenn f sich selbst (indirekt) referenziert. wenn f die Funktion g referenziert und g die Funktion f auch für allgemeinere Fälle (3. N ovember2004) Seite 22 Beispiel: Aufrufhierarchie quadrat x = x*x quadratsumme x y = (quadrat x) + (quadrat y) quadratsumme ruft direkt die Funktion quadrat auf, quadratsumme ruft direkt die (eingebaute) Funktion ∗ auf Die Funktion quadratsumme ist somit nicht rekursiv P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 23 Beispiel: Fakultät 0! := 1 n! := n ∗ (n − 1)! n! ist die Anzahl aller Permutationen einer n-elementigen Menge. rekursive Definition: fakultaet:: Integer -> Integer fakultaet x = if x <= 0 then 1 else x*(fakultaet (x-1)) Diese Funktion ist rekursiv, da sie im Rumpf sich selbst wieder aufruft. P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 24 Entwurf rekursiver Funktionen Wichtig: zwei Fälle sind zu beachten den Basisfall: den Rekursionsfall: Ergebnis: 0 wenn das Argument x ≤ 1 ist. Ergebnis: x*(fakultaet (x-1)), wenn x > 1 ist. Terminierung bei rekursiven Aufrufen : • Argumente werden mit jedem rekursiven Aufruf kleiner fakultaet x ruft fakultaet (x-1) auf für x ≥ 1. • Der Basisfall hat das kleinste Argument Es funktioniert: Main> fakultaet 3 6 Main> fakultaet 40 815915283247897734345611269596115894272000000000 P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 25 Eine falsche Definition fakultaet_nt:: Integer -> Integer fakultaet_nt x = if x == 0 then 1 else x*(fakultaet_nt (x-1)) Diese Funktion terminiert nicht bei negativen Eingaben: fakultaet_nt (-5) ruft fakultaet_nt (-6) auf usw. Für weitere Definitionen von n!, siehe: http://www.willamette.edu/~fruehr/haskell/evolution.html P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 26 Beispiel: Berechnung von Schaltjahren Tropisches Jahr = 365.242190517 6= 365 Tage. Gregorianischen Kalender: Schaltjahre mit 366 Tagen als Korrektur Ein Jahr ist ein Schaltjahr, wenn es durch 4 teilbar ist, aber nicht durch 100. Jahre die durch 400 teilbar sind, sind wieder Schaltjahre. ist_ein_schaltjahr n = if n > 1582 then n ‘mod‘ 400 == 0 || (n ‘mod‘ 4 == 0 && n ‘mod‘ 100 /= 0) else error "Jahreszahl vor Einfuehrung des Gregorianischen Kalenders" P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 27 Beispiel: nächstes Schaltjahr Ermittlung des nächsten Schaltjahres mit j ≥ n: naechstes_schaltjahr n = if (ist_ein_schaltjahr n) then n else naechstes_schaltjahr (n+1) *Main> naechstes_schaltjahr 1997 2000 *Main> naechstes_schaltjahr 2097 2104 *Main> P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 28 Schaltjahre: Orthodox Der orthodoxe Kalender hat bei den durch 100 teilbaren Jahreszahlen eine andere Definition der Schaltjahre: ist_ein_schaltjahr_ortho n = if n > 1582 then (n ‘mod‘ 100 == 0 && (n ‘mod‘ 900 == 200 || n ‘mod‘ 900 == 600)) || (n ‘mod‘ 4 == 0 && n ‘mod‘ 100 /= 0) else error "Jahreszahl vor Einfuehrung" P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 29 Mittlere Jahreslängen mittlere_jahreslaenge::Double mittlere_jahreslaenge = 365.242190517 mittlere_jahreslaenge_gregor = (mittlere_jahreslaenge_sum 2000 2399 0) / 400.0 mittlere_jahreslaenge_sum von bis summe = if von > bis then summe else if ist_ein_schaltjahr von then mittlere_jahreslaenge_sum (von+1) bis (summe + 366) else mittlere_jahreslaenge_sum (von+1) bis (summe + 365) mittlere_jahreslaenge_ortho::Double mittlere_jahreslaenge_ortho = (mittlere_jahreslaenge_ortho_sum 2000 2899 0) / 900.0 mittlere_jahreslaenge_ortho_sum von bis summe = if von > bis then summe else if ist_ein_schaltjahr_ortho von then mittlere_jahreslaenge_ortho_sum (von+1) bis (summe + 366) else mittlere_jahreslaenge_ortho_sum (von+1) bis (summe + 365) P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 30 Unterschied Gregorianisch und Orthodox schaltjahr_anders n = if ist_ein_schaltjahr n == ist_ein_schaltjahr_ortho n then schaltjahr_anders (n+1) else n Welches Jahr ist das erste unterschiedliche nach 2004? P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 31 Problemanalyse und funktionale Abstraktion Zunächst: Algorithmen auf Zahlen Problemanalyse und Erstellung eines Algorithmus: • • • Zerlegung in (einfachere) Teilprobleme Lösen der Teilprobleme mittels Unterfunktionen Zusammensetzen des Algorithmus Wichtig: sekundär: was wie die Funktion leistet, d.h. welche Abbildung wird definiert. die Funktion realisiert wird. Zentrale Leitideen beim Entwurf sind: • Korrektheit • Modularität • Effizienz P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 32 Beispiel: Wurzel aus x mit dem Newtonschen Iterationsverfahren Spezifikation: √ x := y wobei y 2 = x und y ≥ 0 Newton-Verfahren (Heron-Verfahren) √ zur Näherung von x: Starte Iteriere: P raktische Inf ormatik √ mit Schätzwert s für die Wurzel x x s → 0.5(s + ) s bis alter und neuer Schätzwert keine große Differenz mehr aufweisen. 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 33 Beispiel Wurzelberechnung in Haskell wurzel x = wurzeliter 1.0 x wurzeliter schaetzwert x = if gutgenug schaetzwert x then schaetzwert else wurzeliter (verbessern schaetzwert x) x quadrat x = x*x gutgenug:: Double -> Double -> Bool gutgenug schaetzwert x = abs(((quadrat schaetzwert) - x) / x) < 0.000001 mittelwert:: Double -> Double -> Double mittelwert x y = (x + y) / 2.0 verbessern schaetzwert x = mittelwert schaetzwert (x / schaetzwert) *Main> wurzel 2.0 1.4142156862745097 *Main> P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 34 Semantik von Programmiersprachen Semantik = Bedeutung eines Programms (Programmtextes) ausgehend vom Syntaxbaum des Programms. Methoden der Semantik-Definition: Operationale Semantik Denotationale Semantik Transformations-Semantik logische Semantik P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 35 Operationale Semantik Spezifikation von Wirkung und Ablauf: Zustand: Pro Programmkonstrukt: Haskell: Python: Zustand Übergange: Zustand Übergange: Speicherbelegung als Datenstruktur oder . . . Angabe des Zustandsübergangs = Ausdruck sind Reduktionen, d.h. Änderungen der Ausdrücke. = Umgebung Veränderungen des Speicherinhalts. operationale Semantik = Spezifikation eines Interpreters Vorteil: Prinzipiell immer durchführbar P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 36 Denotationale Semantik Zuordnung: Domain D: Pro Programmkonstrukt: Hürden: P raktische Inf ormatik Programm 7→ Funktion Menge der möglichen Funktionen und Objekte rekursive Angabe der Konstruktion einer Funktion in D. Mathematisches Vorwissen notwendig Domainkonstruktion kann schwierig sein 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 37 Transformations-Semantik Vorgehen zur Definition der Semantik eines Programms P : • Semantik bereits für eine Untermenge der Programme erklärt • Transformiere P → . . . → P 0 • Nehme die Semantik von P 0. Verwendung: Semantik einer vollen Programmiersprache erklärt durch: • Semantik der Kernsprache • Transformation: volle Sprache −→ Kernsprache. Semantik von Haskell ist teilweise eine Transformationssemantik Vorteile: P raktische Inf ormatik Vereinfacht Semantik-Definition Analog zur Arbeitsweise von Compilern 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 38 Logische Semantik Beschreibung der Programmkonstrukte und Eigenschaften von Programmen mittels logischer Axiome Herleiten von Programmeigenschaften durch logisches Schließen Z.B. in Prädikatenlogik: Für alle Eingaben n von natürlichen Zahlen liefert quadrat n das Ergebnis n2. Als Formel: ∀n : quadrat(n) = n2 P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 39 Auswertung von einfachen Haskell-Programmen: Ziel: operationale Semantik von Haskell Vorteile einer operationalen Semantik: • formal saubere Definition der Auswertung • auch für Funktionen höherer Ordnung • Unabhängigkeit von Compilern • Unabhängigkeit vom Rechnertyp (Portabilität) P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 40 Einfache Haskell-Programme Definition: Basiswert ist entweder eine Zahl, Zeichen oder True,False. Einfache Haskell-Programme: dürfen benutzen: • Basiswerte und entsprechende vordefinierte Operatoren • Funktionsdefinitionen • if-then-else • Anwendung von Funktionen auf Argumente P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 41 Einfache Haskell-Programme (2) Definition: Ein (einfaches) Haskell-Programm besteht aus: • Menge von Funktionsdefinitionen; entsprechend obiger Beschränkungen • Ausdruck (main) vom Typ eines Basiswertes. Wert des Programms = Wert von main Beispiel quadrat x = x * x kubik x = x * x * x w = 2 main = if w >= 0 then quadrat w else kubik w P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 42 Berechnung und Auswertung Prinzip der Berechnung für einfache Haskell-Programme Folge von Transformationen Auswertung = von main bis ein Basiswert erreicht ist main → t1 → t2 → . . . → tn → . . . Es gibt drei Fälle: 1. Die Folge endet mit einem Basiswert 2. Die Folge endet, aber nicht mit einem Basiswert 3. Die Folge endet nicht Bei 2. und 3.: Wert undefiniert. P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 43 Berechnung und Auswertung: Notation P [t] Bedeutung: P [·] ist ein Ausdruck P mit Platzhalter [·] P [t] bedeutet den Ausdruck P mit t anstelle des Platzhalters Beispiel: P [·] ≡ P [t] ≡ P raktische Inf ormatik if s then [.] else 2, if s then t else 2. 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 44 Auswertung Einfache Haskell-Programm haben drei verschiedene Arten von Auswertungsschritten 1. Definitionseinsetzung (δ-Reduktion) 2. Arithmetische Auswertung 3. Auswertung von Fallunterscheidungen P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 45 Definitionseinsetzung (δ-Reduktion) Auswerten einer Anwendung von f auf n Argumente: P [(f t1 . . . tn)] → P [(Rumpff [t1/x1, . . . tn/xn])] Bedingungen: Die Definition von f ist: f x1 . . . xn = Rumpf f P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 46 Definitionseinsetzung (Rumpff [t1/x1, . . . tn/xn]) entsteht durch (paralleles bzw. unabhängiges) Ersetzen von xi durch ti. ti kann ein Ausdruck sein; es muss kein Basiswert sein! P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 47 Einschub: Metanotation In Lehrbüchern, Skripten, Artikeln über Programmiersprachen, Logik usw.: Mischung von konkreter Syntax und Meta-Notation. Beispiele konkrete Syntax: die Funktion fakultaet . . . “ ” Meta-Notation: Sei f eine Funktion in Programm . . . “, ” P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 48 Einschub: Metanotation: Beispiel Notation bei Definitionseinsetzungsregel : (Rumpff [t1/x1, . . . tn/xn]) Hierbei sind alles Metavariablen: f Rumpff t1, . . . , tn x1 , . . . , x n P raktische Inf ormatik steht für eine Funktion steht für den Rumpf dieser Funktion stehen für Ausdrücke: die Argumente stehen für die formalen Parameter der Funktion 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 49 Einschub: Metanotation: Beispiel gutgenug schaetzwert x = abs(((quadrat schaetzwert) - x)) / x < 0.0000000000001 Bei Definitionseinsetzung für gutgenug 2.0 1.0: x1 steht für den formalen Parameter schaetzwert und x2 steht für den formalen Parameter x t1 steht für den formalen Parameter 2.0 ... P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 50 Arithmetische Auswertungen P [v op w] → P [r] wenn: v, w arithmetische Basiswerte, op ein zweistelliger arithmetischer Operator, r Resultat von v op w P [op v] → P [r] wenn: v arithmetischer Basiswert, op einstelliger arithmetischer Operator, r Resultat von op v Beachte: Wenn s op t ausgewertet werden soll, dann zuerst die Ausdrücke s, t auswerten. P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 51 Boolesche Auswertungen P [v op w] oder P [op w] wobei op einer der Operatoren &&, ||, not sein kann. Wird als Anwendung des Operators auf Argumente ausgewertet. Definitionen, in der Wirkung äquivalent zu den vordefinierten: x && y = if x then y else False x || y = if x then True else y not x = if x then False else True P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 52 Auswertung der Fallunterscheidung Fallunterscheidung (if-Reduktion) P [(if True then e1 else e2)] → P [e1] P [(if False then e1 else e2)] → P [e2] Beachte Diese zwei Regeln können nur angewendet werden, wenn der Bedingungsausdruck zu True oder False ausgewertet ist. P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 53 Transformationen, Reduktionen Wir nennen eine Transformation auch Reduktion und eine Folge von Programmtransformationen auch Reduktionsfolge (oder Auswertung). Beachte: Reduktionen / Transformationen sind zunächst überall im Ausdruck erlaubt. Erst eine Auswertungs-Strategie macht die Auswertung eindeutig. P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 54 Beispiel x && y = if x then y x || y = if x then True bot = bot else False else y Auswertungen unter der Annahme der obigen Definition True && True → if True then True else False → True True && False → if True then False else False → False True || True → if True then True else True → True True || False → if True then True else False → True True && bot → if True then bot else False → bot → bot . . . True || bot → if True then True else bot → True P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 55 Beispiel: Programm: main = quadrat 5 quadrat x = x*x Auswertung als Folge von Transformationen: main → quadrat 5 → 5 * 5 → 25 P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 56 Beispiel: Auswertung Programm: wurzel x = if not (x + 0.1 > x) then error "wurzel: not a number" else if x >= 0 then wurzeliter 1.0 x else error "wurzel: Eingabe negativ" wurzeliter schaetzwert x = if gutgenug schaetzwert x then schaetzwert else wurzeliter (verbessern schaetzwert x) x quadrat x = x*x gutgenug schaetzwert x = abs(((quadrat schaetzwert) - x) / x) < 0.000001 mittelwert x y = (x + y) / 2.0 verbessern schaetzwert x = mittelwert schaetzwert (x / schaetzwert) P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 57 Beispiel Auswertung Folge von Transformationen: wurzel 2.0 (Definitionseinsetzung) if not ( 2.0 + 0.1 > 2.0) then error "wurzel: not a number" else if 2.0 >= 0 then wurzeliter 1.0 2.0 else error "wurzel: Eingabe negativ" P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 58 Beispiel: Auswertung (2) (Auswertung arithmetischer Ausdruck) if not ( 2.1 > 2.0) then error "wurzel: not a number" else if 2.0 >= 0 then wurzeliter 1.0 2.0 else error "wurzel: Eingabe negativ" (Auswertung arithmetischer Ausdruck) if not True then error "wurzel: not a number" else if 2.0 >= 0 then wurzeliter 1.0 2.0 else error "wurzel: Eingabe negativ" (Auswertung Boolescher Ausdruck) if False P raktische Inf ormatik then error "wurzel: not a number" else if 2.0 >= 0 then wurzeliter 1.0 2.0 else error "wurzel: Eingabe negativ" 1, W S 2004/05, F olien Haskell 1, (3rd N ovember2004) Seite 59 Beispiel: Auswertung (3) (if-Auswertung) if 2.0 >= 0 then wurzeliter 1.0 2.0 else error "wurzel: Eingabe negativ" if True then wurzeliter 1.0 2.0 else error "wurzel: Eingabe negativ" wurzeliter 1.0 2.0 if gutgenug 1.0 2.0 then 1.0 else wurzeliter (verbessern 1.0 2.0) P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3rd N ovember2004) Seite 60 2.0 Beispiel: Auswertung (4) (Definitionseinsetzung gutgenug ) if abs((( quadrat 1.0 ) - 2.0)) / 2.0 < 0.000001 else wurzeliter (verbessern 1.0 2.0) 2.0 if abs(((1.0 * 1.0 ) - 2.0)) / 2.0 < 0.000001 else wurzeliter (verbessern 1.0 2.0) 2.0 if abs((1.0 - 2.0 )) / 2.0 < 0.000001 then 1.0 else wurzeliter (verbessern 1.0 2.0) 2.0 if abs(-1.0) / 2.0 < 0.000001 then 1.0 else wurzeliter (verbessern 1.0 2.0) 2.0 P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3rd N ovember2004) Seite 61 then 1.0 then 1.0 Beispiel: Auswertung (5) if 1.0 / 2.0 < 0.000001 then 1.0 else wurzeliter (verbessern 1.0 2.0) 2.0 if 0.5 < 0.000001 then 1.0 else wurzeliter (verbessern 1.0 2.0) 2.0 if False then 1.0 else wurzeliter (verbessern 1.0 2.0) 2.0 wurzeliter (verbessern 1.0 2.0) 2.0 if gutgenug (verbessern 1.0 2.0) 2.0 then (verbessern 1.0 2.0) else wurzeliter (verbessern (verbessern 1.0 2.0) 2.0) 2.0 ... P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3rd N ovember2004) Seite 62 Transformationsmöglichkeiten 3 Auswertungen für quadrat (4+5) : 1. quadrat(4 + 5) → (4 + 5) ∗ (4 + 5) → 9 ∗ (4 + 5) → 9 ∗ 9 → 81 2. quadrat(4 + 5) → (4 + 5) ∗ (4 + 5) → (4 + 5) ∗ 9 → 9 ∗ 9 → 81 3. quadrat(4 + 5) → (quadrat 9) → 9 ∗ 9 → 81 Beobachtungen: • • Ergebnis ist gleich Anzahl der Reduktionen verschieden P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 63 Satz von Church und Rosser Satz (Church-Rosser I) Sei P ein Programm, R1, R2 zwei verschiedene Reduktionsfolgen für main mit jeweiligen Resultat-Basiswerten e1 bzw. e2 dann sind diese Basiswerte gleich, d.h. e1 = e2 P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 64 Werte von Programmen Definition: Sei P ein Programm und main von numerischem oder Booleschem Typ. Der Wert des Programms P ist: e undefiniert (⊥) wenn es eine terminierende Reduktionsfolge, ausgehend von main gibt, die mit dem Basiswert e endet, wenn es keine mit einem Basiswert terminierende Reduktionsfolge ausgehend von main gibt. Damit gilt: Ein einfaches Haskell-Programm hat einen eindeutig definierten Wert unabhängig von der Art der Auswertung P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 65 Reduktionsstrategien Zwei wichtige Reduktionsstrategien Applikative Reihenfolge: Argumentauswertung vor δ-Reduktion Normale Reihenfolge: δ-Reduktion vor Argumentauswertung P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 66 Beschreibung: applikative Reihenfolge werte t0 applikativ aus! Fälle: • • • • t0 ist Basiswert. fertig. t0 ≡ s t, Wenn s kein Funktionsname und keine Anwendung, dann applikativ s t0 ≡ f t1 . . . tn. Wenn ar(f ) ≤ n, dann applikativ ti, 1 ≤ i ≤ ar(f ) von links nach rechts. Wenn ar(f ) ≤ n und alle ti Basiswerte, dann δ-Reduktion. Wenn n < ar(f ), dann fertig: keine Reduktion. t0 ≡ if b then e1 else e2. Wenn b Basiswert, dann if-Reduktion Wenn b kein Basiswert, dann applikativ b P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 67 Beschreibung: normale Reihenfolge werte t0 in normaler Reihenfolge aus. Fälle: • t0 ist Basiswert. fertig. • t0 ≡ s t, Wenn s kein Funktionsname und keine Anwendung. Dann normale R. auf s • t0 ≡ f t1 . . . tn und f keine eingebaute Funktion, Wenn ar(f ) ≤ n, dann δ-Reduktion auf f t1 . . . tar(f ). Wenn ar(f ) > n: keine Reduktion. • t0 ≡ f t1 . . . tn und f ist eingebaute Funktion Wenn ar(f ) ≤ n und Argumente von f keine Basiswerte, dann normale R. auf ar(f ) Argumente von links nach rechts. Wenn ar(f ) ≤ n, und ar(f ) Argumente von f sind Basiswerte, dann eingebaute Funktion aufrufen. Wenn ar(f ) > n: keine Reduktion. • t0 ≡ if b then e1 else e2. Wenn b Basiswert, dann if-Reduktion Wenn b kein Basiswert, dann normale R. auf b P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 68 Beispiel für Reduktionen 3 Auswertungen für quadrat (4+5) : 1. quadrat(4 + 5) → (4 + 5) ∗ (4 + 5) → 9 ∗ (4 + 5) → 9 ∗ 9 → 81 normale Reihenfolge der Auswertung 2. quadrat(4 + 5) → (4 + 5) ∗ (4 + 5) → (4 + 5) ∗ 9 → 9 ∗ 9 → 81 3. quadrat(4 + 5) → (quadrat 9) → 9 ∗ 9 → 81 applikative Reihenfolge der Auswertung P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 69 Prozeduraufrufe in anderen Programmiersprachen Prozeduraufruf mit Wertübergabe: call-by-value Es wird nur der Wert übergeben ähnlich zur applikative Reihenfolge Prozeduraufruf mit Namensübergabe: call-by-name Es wird nur der Name der Variablen übergeben hat entfernte Ähnlichkeit zur normalen Reihenfolge P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 70 Satz 2 von Church und Rosser SATZ (Church-Rosser-2) Sei P ein einfaches Haskell-Programm. Wenn es irgendeine Reduktionsfolge für main gibt, die mit einem Basiswert e terminiert, dann terminiert auch die normale Reihenfolge der Auswertung von main und liefert als Basiswert (Resultat) genau e. Die normale Reihenfolge ist ausreichend zur Auswertung Haskell benutzt normale Reihenfolge der Auswertung P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 71 Berechnungsvorschrift Eine Menge von Funktionsdefinitionen, ein Ausdruck und eine ausführbare Auswertungsstrategie ergibt eine Berechnungsvorschrift. Church-Rosser-1 und Church-Rosser-2 =⇒ Funktionsdefinitionen + Ausdruck = Algorithmus P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 72 Gegenbeispiel zu C.R. 2 bei applikativ Church-Rosser-2 gilt nicht für die applikative Reihenfolge: nt x = nt x proj x y = x main = proj 0 (nt 1) applikative Reihenfolge für main terminiert nicht: (nt 1) → (nt 1) → (nt 1) → . . . . . . Deshalb: proj 0 (nt 1) → proj 0 (nt 1) → . . . . . . Die normale Reihenfolge liefert sofort 0. P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 73 Optimale Anzahl der Reduktionen Definition verzögerte Reihenfolge der Auswertung (lazy reduction): • • • normale Reihenfolge gerichteter Graph statt Text Vermeidung von unnötiger Doppelauswertung durch gemeinsame Unterausdrücke (Sharing) Church-Rosser-2 gilt auch für verzögerte Reduktion! Falls ein Basiswert berechnet wird, gilt für #Reduktionsschritte: # verzögerte R ≤ # applikative R ≤ # normale R Es gilt: verzögerte Reduktion hat optimale Anzahl von Reduktionen Haskell verwendet verzögerte Reduktion P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 74 Beispiel 1. 4 Reduktionen: (normale R.) quadrat(4 + 5) → (4 + 5) ∗ (4 + 5) → 9 ∗ (4 + 5) → 9 ∗ 9 → 81 2. 4 Reduktionen: quadrat(4 + 5) → (4 + 5) ∗ (4 + 5) → (4 + 5) ∗ 9 → 9 ∗ 9 → 81 3. 3 Reduktionen (applikative R.) quadrat(4 + 5) → (quadrat 9) → 9 ∗ 9 → 81 4. 3 Reduktionen (verzögerte R.) quadrat(4 + 5) → (4 + 5)(1) ∗ (4 + 5)(1) → 9 ∗ 9 → 81 P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 75 Verzögerte Auswertung: komplexeres Beispiel fakultaet x = if x <= 0 then 1 else x*(fakultaet (x-1)) Die Reduktionsschritte: fakultaet 3 if 3 <= 0 then 1 else 3*(fakultaet (3-1)) if False then 1 else 3*(fakultaet (3-1)) 3* (fakultaet (3-1)) 3*(if (3-1) <= 0 then 1 else (3-1) *(fakultaet ( (3-1) -1))) P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 76 Beispiel . . . 3*(if 2 <= 0 then 1 else 2*(fakultaet (2-1))) 3* (if False then 1 else 2*(fakultaet (2-1))) 3*(2* (fakultaet (2-1)) ) 3*(2*(if (2-1) <= 0 then 1 else (2-1) *(fakultaet ( (2-1) -1)))) 3*(2*(if 1 <= 0 then 1 else 1*(fakultaet (1-1)))) 3*(2* (if False then 1 else 1*(fakultaet (1-1))) ) 3*(2*(1* (fakultaet (1-1)))) P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 77 Beispiel . . . 3*(2*(1*(if (1-1)<= 0 then 1 else(1-1)*(fakultaet ((1-1)-1))))) 3*(2*(1*(if 0 <= 0 then 1 else 0*(fakultaet (0-1))))) 3*(2*(1* (if True then 1 else 0*(fakultaet (0-1))))) 3*(2* (1*1)) 3*(2*1) 3*2 6 P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 78 Ein weiterer Vorteil der verzögerten Reduktion verzögerte Reduktionenen zur Compile-Zeit sind korrekte Programmtransformationen d.h. die operationale Semantik bleibt erhalten Das ist falsch bei applikativer Reihenfolge P raktische Inf ormatik 1, W S 2004/05, F olien Haskell 1, (3. N ovember2004) Seite 79