Funktionale Programmierung - Software and Systems Engineering

Werbung
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
Herunterladen