Technische Universität München Grundlagen der Programm- und Systementwicklung Funktionale Programmierung Teil 2 Methodik: Spezifikation, Implementierung, Verifikation Technische Universität München Institut für Informatik Software Engineering Vortragender: Prof. Dr. Alexander Pretschner Übung: Dipl.-Inf. Florian Kelbert, Dr. Alexander Malkis Folien: Prof. Dr. Dr. h.c. Manfred Broy, Dr. Alexander Malkis, Prof. Dr. Alexander Pretschner, Dr. Maria Spichkova, … 1 Technische Universität München Vorlesungsplanung (siehe Webseite) Einführung Grundbegriffe und Definitionen, Bedeutung und Stellenwert Kernaufgaben, Aktueller Stand der Forschung und Praxis Themen Daten und Rechenstrukturen Konzepte Spezifikation Verifikation von Eigenschaften Funktionale Programme Konzepte Spezifikation Verifikation von Eigenschaften Anweisungs- und objektorientierte Programme Spezifikation Verifikation von Eigenschaften Referenzen und Zeiger Pretschner WS 14/15 Grundlagen der Programm- und Systementwicklung: Funktionale Programmierung: Methodik 2 Technische Universität München Methodik funktionaler Programmierung Spezifikation Entwurf und Implementierung Verifikation Partielle Korrektheit Terminierung Konzepte funktionaler Programmierung Funktionen höherer Ordnung Currying Pretschner WS 14/15 Grundlagen der Programm- und Systementwicklung: Funktionale Programmierung: Methodik 3 Technische Universität München Spezifikation funktionaler Programme Funktionale Programme bestehen aus einer Familie rekursiver Deklarationen von Funktionen. Die Spezifikation eines funktionalen Programms entspricht somit der Angabe der Funktionalität/Sorten und der Charakterisierung dieser Familie von Funktionen durch logische Eigenschaften. Algebraische Spezifikation einer Funktion f: die Funktionalität von f (ihre Funktionssorte), eine Anzahl von Gleichungsaxiomen und ggf. Definiertheitsaxiome Prädikative Spezifikation einer Funktion f: Funktionen werden durch ihre charakteristischen Eigenschaften beschrieben, nicht nur Gleichungen sondern allgemeine (auch nichtmonotone) Prädikate, es wird ein beliebiger prädikatenlogischer Ausdruck für die Spezifikation verwendet, ein verbreitetes Format: zwei Prädikate – „Vor- und Nachbedingung“ – Assumption/Commitment Pretschner WS 14/15 Grundlagen der Programm- und Systementwicklung: Funktionale Programmierung: Methodik 4 Technische Universität München Mustersuche in einem Text Gesucht ist Funktion search: Seq Char, Seq Char Nat , die eine Position des Musters m : Seq Char (wenn vorhanden) im Text x : Seq Char liefert, d.h. mit ( i Nat: found(x, i, m) = true) ⇒ found(x, search(x, m), m) = true , wobei found: Seq Char, Nat, Seq Char Bool found(x, n, m) = true ⇔ ( s, r Seq Char: x = s∘m∘r n = #s) . Pretschner WS 14/15 Grundlagen der Programm- und Systementwicklung: Funktionale Programmierung: Methodik 5 Technische Universität München Mustersuche in einem binären gewurzelten Baum Gesucht ist Funktion search: Tree Char, Tree Char Seq Bool die eine Position des Musters m : Tree Char (wenn vorhanden) im Baum x : Tree Char liefert, d.h. mit ( p Seq Bool: found(x, p, m) = true) found(x, search(x, m), m) = true , wobei found: Tree Char, Seq Bool, Tree Char Bool found(x, ‹›, m) = true ⇔ x = m found(etree, ‹b› p, m) = false found(x, ‹false› p, m) = found(left(x), p, m) found(x, ‹true› p, m) = found(right(x), p, m) Pretschner WS 14/15 Grundlagen der Programm- und Systementwicklung: Funktionale Programmierung: Methodik 6 Technische Universität München Erreichbarkeit in Graphen Gegeben: Graph durch Funktion g: Node Fset Node liefert zu jedem Knoten n die Menge g(n) der durch eine Kante erreichbaren Knoten Gesucht: Funktion reach: Node Fset Node die zu jedem Knoten n die Menge reach(n) der in g durch eine Folge von Kanten (einen „Pfad“) erreichbaren Knoten liefert. Pretschner WS 14/15 Grundlagen der Programm- und Systementwicklung: Funktionale Programmierung: Methodik 7 Technische Universität München Prädikative Spezifikation m reach(n) = s Seq Node: ispath(n, s, m) wobei ispath : Node, Seq Node, Node Bool durch die folgende algebraische Spezifikation beschrieben wird: ispath(n, ‹›, m) = true ⇔ n=m ispath(n, ‹a› ∘ s, m) = and(isel(g(n), a) , ispath(a, s, m)) Pretschner WS 14/15 Grundlagen der Programm- und Systementwicklung: Funktionale Programmierung: Methodik 8 Technische Universität München Spezifikation vs. funktionales Programm Für ein Funktionssymbol f mit Funktionalität f : M1 , ... , Mn Mn+1 und ein spezifizierendes Prädikat (Spezifikation einer Funktion) R: (M1 , ... , Mn Mn+1) IB formulieren wir die Aussage, dass f die Spezifikation R erfüllt: f sat R (oder auch R(f)) Pretschner WS 14/15 Grundlagen der Programm- und Systementwicklung: Funktionale Programmierung: Methodik 9 Technische Universität München Assumption/Commitment - Spezifikation Für ein Funktionssymbol f : M1 , ... , Mn Mn+1 erhalten wir eine Spezifikation assume(x1 , ... , xn) = true commit(x1 , ... , xn, f(x1 , ... , xn)) = true beschrieben durch die Prädikate assume : M1 , ... , Mn Bool und commit : M1 , ... , Mn, Mn+1 Bool Beispiel: insort: Seq Nat, Seq Nat → Seq Nat is_sorted(s) = true and(is_sorted(insort(r, s)), insort(r, s) ros) = true mit is_sorted: Seq Nat Bool Sequenz ist sortiert _ _: Seq Nat, Seq Nat Bool Sequenzen haben gleiche Elemente Das Assume-Prädikat ist (r: Seq Nat, s: Seq Nat) Bool: is_sorted(s) . Das Commit-Prädikat ist (r: Seq Nat, s: Seq Nat, f: (Seq Nat, Seq Nat → Seq Nat)) Bool: and(is_sorted(f(r, s)), f(r, s) ~ ros) . Pretschner WS 14/15 Grundlagen der Programm- und Systementwicklung: Funktionale Programmierung: Methodik 10 Technische Universität München BEWEISEN VON EIGENSCHAFTEN FÜR FUNKTIONALE PROGRAMME Pretschner WS 14/15 Grundlagen der Programm- und Systementwicklung: Funktionale Programmierung: Methodik 11 Technische Universität München Deklaration – Aussagen Gegeben rekursive Deklaration fct f = (x1 : M1, ..., xn : Mn)Mn+1 : t Für f gilt die Gleichung: f(x1, ..., xn) = t Weiter gilt: f ist die am wenigsten definierte Funktion, die die Gleichung erfüllt: ( x1, ..., xn : g(x1, ..., xn) = t[g/f] ) f ⊑ g Wenn wir Aussagen über f beweisen wollen, können wir uns auf diese Eigenschaft stützen. Pretschner WS 14/15 Grundlagen der Programm- und Systementwicklung: Funktionale Programmierung: Methodik 12 Technische Universität München Beweisprinzipien für Rekursion Berechnungsinduktion Beweise durch Fixpunkteigenschaften Strukturelle Induktion Pretschner WS 14/15 Grundlagen der Programm- und Systementwicklung: Funktionale Programmierung: Methodik 13 Technische Universität München Beweisprinzipien für Rekursion: Berechnungsinduktion Die Berechnungsinduktion: erlaubt induktive Beweise von Eigenschaften für rekursiv deklarierte Funktionen, falls das auftretende Funktional stetig ist. das zu beweisende Prädikat muss gewisse Eigenschaften haben. Zulässigkeit des Prädikates. Pretschner WS 14/15 Grundlagen der Programm- und Systementwicklung: Funktionale Programmierung: Methodik 14 Technische Universität München Beweisprinzipien für Rekursion: Berechnungsinduktion Sei (X,⊑) eine vollständige Halbordnung. Ein Prädikat φ: X → IB heißt zulässig (engl. admissible), falls für jede gerichtete Menge N⊆X gilt: (∀ a∈N: φ(a)) ⇒ φ(sup N) . Beachte: Unsere Definition der Vollständigkeit für Halbordnungen fordert die Existenz von Suprema für alle gerichtete Mengen, insbesondere für die leere Menge. Ist also ⊥∈X das kleinste Element einer vollständigen Halbordnung, so gilt φ(⊥) für jedes zulässige Prädikat φ auf X. Pretschner WS 14/15 Grundlagen der Programm- und Systementwicklung: Funktionale Programmierung: Methodik 15 Technische Universität München Beispiele: ein zulässiges und ein unzulässiges Prädikat Ist (X,⊑) eine vollständige Halbordnung und g ∊ X, so ist φ: X→𝔹, f ↦ (f⊑g) ein zulässiges Prädikat auf X. Beweis: Sei N⊆X gerichtet mit ∀ f∊N: φ(f). Dann gilt ∀ f∊N: f⊑g, also sup⊑(N) ⊑ g. Sei ℕ⊥ mit flacher Halbordnung ≼ versehen, und sei ℕ⊥→ℕ⊥ punktweise partiell geordnet: f ⊑ g gdw. ∀ x∊ℕ⊥: f(x) ≼ g(x) (f,g ∈ ℕ⊥→ℕ⊥). Dann ist (ℕ⊥→ℕ⊥, ⊑) eine vollständige Halbordnung und φ: (ℕ⊥→ℕ⊥)→𝔹, f ↦ (idℕ⊥⋢f) ein nicht zulässiges Prädikat. Beweis: (ℕ⊥→ℕ⊥, ⊑) vollständige Halbordnung: ist F ⊆ (ℕ⊥→ℕ⊥) gerichtet, so ist λ x∊ℕ⊥. sup≼{f(x) | f ∊ F} wohldefiniert und gleich sup⊑(F). φ nicht zulässig: N = { f: ℕ⊥→ℕ⊥ | f(⊥)=⊥ ∧ ∃ n∈ℕ: ((∀ x<n: f(x)=x) ∧ (∀ x≥n: f(x)=⊥)) } ist gerichtet, idℕ⊥⋢ f gilt für alle f ∊ N, aber sup⊑(N) = idℕ⊥. Pretschner WS 14/15 Grundlagen der Programm- und Systementwicklung: Funktionale Programmierung: Methodik 16 Technische Universität München Beweisprinzipien für Rekursion: Berechnungsinduktion Hierbei ist fix τ der kleinste Fixpunkt von τ. Pretschner WS 14/15 Grundlagen der Programm- und Systementwicklung: Funktionale Programmierung: Methodik 17 Technische Universität München Beweise durch Fixpunkteigenschaften Aus den Fixpunkteigenschaften lassen sich Eigenschaften für eine rekursiv deklarierte Funktion f beweisen. Dies funktioniert aber nur für Eigenschaften, die für alle Fixpunkte gelten. Pretschner WS 14/15 Grundlagen der Programm- und Systementwicklung: Funktionale Programmierung: Methodik 18 Technische Universität München Beweise durch Fixpunkteigenschaften Fixpunkt von τ ist. Pretschner WS 14/15 Grundlagen der Programm- und Systementwicklung: Funktionale Programmierung: Methodik 19 Technische Universität München Beweise durch Fixpunkteigenschaften Um τ(g)=g zu zeigen, zeigen wir per Induktion über a, dass ∀a,b ∈ Nat: (τ(g))(a,b) = g(a,b) : Für alle a,b ∈ Nat gilt: (τ(g))(a,b) = if a=0 then b else g(a-1, a*b) fi = if a=0 then b else (a-1)!*a*b fi = if a=0 then b else a!*b fi = a!*b = g(a,b) . Pretschner WS 14/15 Grundlagen der Programm- und Systementwicklung: Funktionale Programmierung: Methodik 20 Technische Universität München Pretschner WS 14/15 Grundlagen der Programm- und Systementwicklung: Funktionale Programmierung: Methodik 21 Technische Universität München Beweisprinzipien für Rekursion: Strukturelle Induktion Schließlich können wir Beweise über rekursiv definierte Funktionen auch führen, indem wir klassische Beweisprinzipien der Induktion bezüglich der Argumentbereiche zusammen mit der Fixpunkteigenschaft verwenden. Dies erfordert eine Noethersche Ordnung auf dem Definitionsbereich. Pretschner WS 14/15 Grundlagen der Programm- und Systementwicklung: Funktionale Programmierung: Methodik 22 Technische Universität München Beweisprinzipien für Rekursion: Induktion … indem wir lediglich ausnutzen, dass reverse die folgende Gleichung erfüllt: τ(reverse) = reverse für das dazugehörige Funktional τ, sprich, (λx. if iseseq(x) then x elif iseseq(rest(x)) then x else reverse(rest(x))o〈first(x)〉 fi) = reverse , oder äquivalent ∀ x: ((if iseseq(x) then x elif iseseq(rest(x)) then x else reverse(rest(x))o〈first(x)〉 fi) = reverse(x)). Wir werden hier nicht ausnutzen, dass reverse die kleinste Lösung der Gleichung ist (in der Tat gibt es keine größere). Pretschner WS 14/15 Grundlagen der Programm- und Systementwicklung: Funktionale Programmierung: Methodik 23 Technische Universität München Beispiel: Induktion über ℕ Lemma: ∀ s,t ∈ Seq α : reverse(s∘t) = reverse(t)∘reverse(s). Beweis: Durch Induktion über die Länge von s. Sei s ∈ Seq α beliebig, fest. Wir nehmen an, dass ∀ s’ ∈ Seq α : |s’|<|s| ⇒ ∀ t ∈ Seq α : reverse(s’∘t) = reverse(t)∘reverse(s’) und zeigen ∀ t ∈ Seq α : reverse(s∘t) = reverse(t)∘reverse(s). Sei t ∈ Seq α beliebig, fest. Falls s=ε, so reverse(s∘t) = reverse(t) = reverse(t)∘ε = reverse(t)∘reverse(s). Falls s=〈a〉 und t=ε, so reverse(s∘t) = reverse(〈a〉) = reverse(s)∘reverse(t). Falls s=〈a〉 und t≠ε, so reverse(s∘t) = reverse(〈a〉∘t) [Def. von reverse] = reverse(t)∘〈a〉 = reverse(t)∘reverse(s). Falls ε≠s≠〈a〉, so reverse(s∘t) [Axiome über first, rest] = reverse((〈first(s)〉∘rest(s))∘t) [Assoziativität] = reverse(〈first(s)〉∘(rest(s)∘t)) [Def. von reverse] = reverse(rest(s)∘t)∘〈first(s)〉 [Induktions-Annahme] = (reverse(t)∘reverse(rest(s)))∘〈first(s)〉 [Assoziativität] = reverse(t)∘(reverse(rest(s))∘〈first(s)〉) [Def. von reverse] = reverse(t)∘reverse(〈first(s)〉∘rest(s)) [Axiome über first, rest] = reverse(t)∘reverse(s). Pretschner WS 14/15 Grundlagen der Programm- und Systementwicklung: Funktionale Programmierung: Methodik 24 Technische Universität München Beispiel: strukturelle Induktion Satz: ∀ s ∈ Seq α : reverse(reverse(s)) = s. Beweis: Durch Induktion über die Teilzeichenkette-Relation. Sei s ∈ Seq α beliebig, fest. Wir nehmen an, dass ∀ r ∈ Seq α : r echte Teilzeichenkette von s ⇒ reverse(reverse(r)) = r. und zeigen reverse(reverse(s)) = s. Falls s=ε, so reverse(reverse(s)) = reverse(reverse(ε)) = reverse(ε) = ε = s. Falls s=〈a〉, so reverse(reverse(s)) [Def. von reverse] = reverse(〈a〉) = 〈a〉. Falls ε≠s≠〈a〉, so reverse(reverse(s)) [Axiome über first, rest] = reverse(reverse((〈first(s)〉∘rest(s))) [Def. von reverse] = reverse(reverse(rest(s))∘〈first(s)〉) [Lemma] = reverse(〈first(s)〉)∘reverse(reverse(rest(s))) [Def. von reverse] = 〈first(s)〉∘reverse(reverse(rest(s))) [Induktions-Annahme] = 〈first(s)〉∘rest(s) [Axiome über first, rest] = s. Pretschner WS 14/15 Grundlagen der Programm- und Systementwicklung: Funktionale Programmierung: Methodik 25 Technische Universität München Terminierungsbeweise Abstiegsfunktion (Bewertungsfunktion) Beweis: Schema Beispiele Pretschner WS 14/15 Grundlagen der Programm- und Systementwicklung: Funktionale Programmierung: Methodik 26 Technische Universität München Terminierungsbeweise Pretschner WS 14/15 Grundlagen der Programm- und Systementwicklung: Funktionale Programmierung: Methodik 27 Technische Universität München Terminierungsbeweise Pretschner WS 14/15 Grundlagen der Programm- und Systementwicklung: Funktionale Programmierung: Methodik 28 Technische Universität München Terminierungsbeweise Pretschner WS 14/15 Grundlagen der Programm- und Systementwicklung: Funktionale Programmierung: Methodik 29 Technische Universität München Terminierungsbeweis: Beispiel Sei p(x,y) = (x=0 ∨ y>0). (Streng genommen or(iszero(x) , not(iszero(y))) .) Pretschner WS 14/15 Grundlagen der Programm- und Systementwicklung: Funktionale Programmierung: Methodik 30 Technische Universität München Terminierungsbeweis: Beispiel Seien feste x,y ∈ Nat mit p(x,y) gewählt, d.h. x=0 ∨ y>0. Wir nehmen an, dass für alle (x’,y’) mit p(x’,y’) und h(x’,y’)<h(x,y) die Formel Def[f(x’,y’)] gilt. Wir zeigen, dass Def[f(x,y)] gilt. • Induktionsanfang (Fall h(x,y)=0): Wegen h(x,y)=0 gilt x≤y. Dann ist Funktionsrumpf[Ω/f] = if x≤y then y else Ω(x,2*y) fi = y definiert. • Induktionsschritt (Fall h(x,y)>0): Wegen h(x,y)>0 ist if x≤y then 0 else x-y fi > 0, also h(x,y) = x-y und x>y. Dann x≠0. Wegen p(x,y) muss also y>0 gelten. Daher ist 2*y>y und x-2*y < x-y, daher h(x,2*y) ≤ x-2*y < h(x,y). Nach Induktionsannahme gilt Def[f(x,2*y)]. Dann gilt auch Def[if x≤y then y else f(x,2*y) fi]. Pretschner WS 14/15 Grundlagen der Programm- und Systementwicklung: Funktionale Programmierung: Methodik 31 Technische Universität München Funktionale Sorten Gewünscht: in Programmen (und ihren Spezifikationen) Funktionen als Parameter zulassen. Bsp.: Ordnungsrelation für Sortieroperation, Prädikate für Filtrierung einer Liste, beliebige Operation für foldl-Funktion auf Listen. Pretschner WS 14/15 Grundlagen der Programm- und Systementwicklung: Funktionale Programmierung: Methodik 32 Technische Universität München Funktionale Sorten: Beispiel 1. Stufe: 2. Stufe: 2. Stufe: 3. Stufe: f1: Nat → Nat f2: (Nat → Nat), Nat → Nat f3: Nat → (Nat → Nat) f4: ((Nat → Nat), Nat → Nat), Nat → (Nat → Nat) Pretschner WS 14/15 Grundlagen der Programm- und Systementwicklung: Funktionale Programmierung: Methodik 33 Technische Universität München Funktionsabstraktion - Motivation Gewünscht: - trivialen Funktionen keinen Namen geben. - Funktionen im Kontext bereits gebundener Variablen definieren. Beispiel aus Scheme: (filter (lambda (x) (equal? x 1)) '(1 2 3)) => (1) . Beispiel aus Haskell: Prelude> foldl (\x y -> concat ["(",x,"+",y,")"]) "0" (map show [1..13]) "(((((((((((((0+1)+2)+3)+4)+5)+6)+7)+8)+9)+10)+11)+12)+13)" . Beispiel aus OCaml: (let one = 1 in List.sort (fun x y -> if (one*x)>y then 1 else 0)) [5;3;7;1];; liefert - : int list = [1; 3; 5; 7] . Wir formalisieren namenlose Funktionen wie folgt. Pretschner WS 14/15 Grundlagen der Programm- und Systementwicklung: Funktionale Programmierung: Methodik 34 Technische Universität München Funktionsabstraktion - Definition Eine Funktionsabstraktion ist ein Term (x1: M1, …, xn: Mn) Mn+1 : t , wobei M1, …, Mn+1 Sorten sind, falls jedes xi im Term t die Sorte Mi hat (1≤i≤n), so hat t die Sorte Mn+1. Die freien Identifikatoren (freien Variablen) der Funktionsabstraktion wie oben sind die freien Variablen von t ohne x1, …, xn. Beispiel: Sei fct f2 = (g: (Nat)Nat, z: Nat) Nat : g(z)+z . Der Term f2((x: Nat)Nat: x+succ(0), succ(0)) = ((g: (Nat)Nat, z: Nat) Nat : g(z)+z) ((x: Nat)Nat: x+succ(0), succ(0)) kann zu ((x: Nat)Nat: x+succ(0)) (succ(0))+succ(0) und dann zu (succ(0)+succ(0))+succ(0) reduziert werden. Über ℕ ist die Interpretation des letzten Terms gleich 3. Pretschner WS 14/15 Grundlagen der Programm- und Systementwicklung: Funktionale Programmierung: Methodik 35 Technische Universität München Currying Gewünscht: - In der Theorie: ohne Tupel-Schreibweise auskommen. - In der Praxis: partielle Evaluation von Termen wie f(3,5,x). Lösung: Funktion curryi (sei i ℕ, 1 i n) Benannt nach dem Logiker Haskell Curry (1900-1982), gleichzeitig Namenspatron für die funktionale Programmiersprache Haskell. Statt curry1 schreiben wir curry. Pretschner WS 14/15 Grundlagen der Programm- und Systementwicklung: Funktionale Programmierung: Methodik 36 Technische Universität München Currying: Beispiel Sei add: Nat, Nat → Nat mit Interpretation der Addition über ℕ. Dann ist curry(add): Nat → Nat → Nat mit curry(add)(n) = (m: Nat) Nat: add(n,m) . Die Interpretation des Terms curry(add)(succ(succ(succ(succ(succ(0)))))) über ℕ ist die Funktion, die zu jedem Argument 5 hinzuzählt. Pretschner WS 14/15 Grundlagen der Programm- und Systementwicklung: Funktionale Programmierung: Methodik 37 Technische Universität München Funktionskomposition und Formale Parameter Relationale Komposition f ∘ g zweier Funktionen f, g mit f: M1 M2 g: M2 M3 ist eine polymorphe Funktion höherer Stufe mit Funktionssorte f ∘ g : (1 2), (2 3) (1 3) Es gilt: (f ∘ g)(x) = g(f(x)) Gebundene vs. freie Bezeichnungen: Beispiel Pretschner WS 14/15 Grundlagen der Programm- und Systementwicklung: Funktionale Programmierung: Methodik 38 Technische Universität München Tupel Gewünscht: - (Theorie) in einigen Fällen statt viele Funktionen großer Stelligkeit nur eine Funktion beliebiger Stelligkeit und die restlichen Funktionen einstellig haben. - oder (Praxis) einen Satz von Argumenten als eine Einheit betrachten. Lösung: Tupelsorten [M1, ..., Mn], ähnlich zu Produktsorten und Records. Tupelbildende Funktion [ _, ..., _ ] : M1, ..., Mn [M1, ..., Mn] Strikte Tupelbildung Tupelbildende Funktion wird als strikt angenommen. Tupel enthalten dann niemals das Pseudoelement als Eintrag. Mengenprodukt als Trägermenge für die Tupelsorte [M1, ..., Mn] : ((M1 \ {}) ... (Mn \ {}) ) {} Nichtstrikte Tupelbildung Tupelbildende Funktion wird als nichtstrikt angenommen. Mengenprodukt als Trägermenge für die Tupelsorte [M1, ..., Mn] : (M1 ... Mn) \ {(,..., )} {} Pretschner WS 14/15 Grundlagen der Programm- und Systementwicklung: Funktionale Programmierung: Methodik 39 Technische Universität München Zwei schwächere Formen der Erfüllung einer Spezifikation Eine Funktion f ist partiell korrekt bezüglich der Spezifikation R: f satpar R g: f ⊑ g R(g) f liefert Resultate, wie in der Spezifikation gefordert, falls sie terminiert. Die Terminierung von f ist jedoch nicht garantiert, selbst wenn sie in der Spezifikation R gefordert wird. Eine Funktion f ist robust korrekt bezüglich der Spezifikation R: f satrob R g: g ⊑ f R(g) f terminiert für alle Fälle, die durch die Spezifikation gefordert werden f liefert dann Werte wie spezifiziert. Sogar in Fällen, in denen die Spezifikation keine Terminierung fordert und keine Werte vorschreibt, kann f terminieren (und beliebig gewählte Werte liefern). Pretschner WS 14/15 Grundlagen der Programm- und Systementwicklung: Funktionale Programmierung: Methodik 40 Technische Universität München Partielle und robuste Korrektheit: Beispiele fct div1 = (x,y: Nat) Nat: if x<y then 0 else div1(x-y, y)+1 fi fct div2 = (x,y: Nat) Nat: if y=0 ∨ x<y then 0 else div2(x-y, y)+1 fi fct div3 = (x,y: Nat) Nat: if x<y then 0 else div3(x-2*y, y)+2 fi (mit ∀ x,y∈ Nat : x<2*y ⇒ x-2*y=⊥) R(f) = ∀ x,y∈ Nat: ( ( y>0 ⇒ y*f(x,y) ≤ x < y*(f(x,y)+1) ) ∧ ( y=0 ⇒ f(x,y) = ⊥) ) div1 sat R, da R(div1). div2 satrob R, da div1⊑div2 ∧ R(div1). div3 satpar R, da div3⊑div1 ∧ R(div1). Pretschner WS 14/15 Grundlagen der Programm- und Systementwicklung: Funktionale Programmierung: Methodik 41 Technische Universität München Abschließende Bemerkungen Funktionale Programmierung Vorteile wenige einfache transparente Konzepte klare Semantik hohe Unabhängigkeit von technischen Details hohe Modularität Nachteile Heutige Maschinen arbeiten nach dem von Neumann-Konzept (Prozessor/Speicher/Instruktion) Hohe Effizienz auf heute gängigen Maschinen nicht vollständig erreichbar Pretschner WS 14/15 Grundlagen der Programm- und Systementwicklung: Funktionale Programmierung: Methodik 42