Praktische Informatik 3 (WS 2010/11) - informatik.uni

Werbung
Fahrplan
Praktische Informatik 3: Einführung in die Funktionale
Programmierung
Vorlesung vom 05.01.2011: Signaturen und Eigenschaften
I
Teil I: Funktionale Programmierung im Kleinen
I
Teil II: Funktionale Programmierung im Großen
I
Abstrakte Datentypen
I
Signaturen und Eigenschaften
I
Aktionen und Zustände
Christoph Lüth & Dennis Walter
Universität Bremen
Wintersemester 2010/11
I
Rev. 1312
Teil III: Funktionale Programmierung im richtigen Leben
2 [26]
1 [26]
Abstrakte Datentypen
Signaturen
I
Letzte Vorlesung: Abstrakte Datentypen
Definition (Signatur)
I
Typ plus Operationen
Die Signatur eines abstrakten Datentyps besteht aus den Typen, und der
Signatur der darüber definierten Funktionen.
I
I
In Haskell: Module
Heute: Signaturen und Eigenschaften
I
Keine direkte Repräsentation in Haskell
I
Signatur: Typ eines Moduls
3 [26]
Zur Erinnerung: Endliche Abbildungen
4 [26]
Endliche Abbildung: Signatur
I
I
Endliche Abbildung (FiniteMap)
I
Typen: die Abbildung S, Adressen a, Werte b
I
Operationen (Auszug)
I
leere Abbildung: S
I
Abbildung an einer Stelle schreiben: S → a → b → S
I
Abbildung an einer Stelle lesen: S → a * b (partiell)
Adressen und Werte sind Parameter
type Map α β
I
Leere Abbildung:
empty :: Map α β
I
An eine Stelle einen Wert schreiben:
insert
I
:: Map α β → α → β → Map α β
An einer Stelle einen Wert lesen:
lookup
:: Map α β → α → Maybe β
5 [26]
Signatur und Eigenschaften
6 [26]
Beschreibung von Eigenschaften
Definition (Axiome)
I
Axiome sind Prädikate über den Operationen der Signatur
Signatur genug, um ADT typkorrekt zu benutzen
I
I
I
Elementare Prädikate P :
Insbesondere Anwendbarkeit und Reihenfolge
Signatur nicht genug, um Bedeutung (Semantik) zu beschreiben:
I
Was wird gelesen?
I
Wie verhält sich die Abbildung?
I
7 [26]
I
Gleichheit s ==t
I
Ordnung s < t
I
Selbstdefinierte Prädikate
Zusammengesetzte Prädikate
I
Negation not p
I
Konjunktion p && q
I
Disjunktion p | | q
I
Implikation p =⇒ q
8 [26]
Beobachtbare und Abstrakte Typen
Axiome für Map
I
I
I
Beobachtbare Typen: interne Struktur bekannt
I
l o o k u p empty a == N o t h i n g
I
Vordefinierte Typen (Zahlen, Zeichen), algebraische Datentypen (Listen)
I
Viele Eigenschaften und Prädikate bekannt
I
Lesen an vorher geschriebener Stelle liefert geschriebenen Wert:
I
Lesen an anderer Stelle liefert alten Wert:
l o o k u p ( i n s e r t m a b ) a == J u s t b
Abstrakte Typen: interne Struktur unbekannt
I
Lesen aus leerer Abbildung undefiniert:
a1 /= a2 =⇒ l o o k u p ( i n s e r t m a1 b ) a2 ==
l o o k u p m a2
Wenig Eigenschaft bekannt, Gleichheit nur wenn definiert
I
Beispiel Map:
Schreiben an dieselbe Stelle überschreibt alten Wert:
i n s e r t (m a b1 ) a b2 == i n s e r t m a b2
I
beobachtbar: Adressen und Werte
I
abstrakt: Speicher
I
Schreiben über verschiedene Stellen kommutiert:
a1 /= a2 =⇒ i n s e r t ( i n s e r t m a1 b1 ) a2 b2 ==
i n s e r t ( i n s e r t m a2 b2 ) a1 b1
9 [26]
Axiome als Interface
I
I
I
empty ::
nach außen das Verhalten
nach innen die Implementation
Signatur + Axiome = Spezifikation
Nutzer
Spezifikation
Implementation
St α
empty :: Qu α
Wert ein/auslesen:
Wert ein/auslesen:
push
top
pop
enq :: α→ Qu α→ Qu α
f i r s t :: Qu α→ α
deq :: Qu α→ Qu α
:: α→ St α→ St α
:: St α→ α
:: St α→ St α
Test auf Leer:
isEmpty
I
Implementation kann getestet werden
I
Axiome können (sollten?) bewiesen werden
Queues
Typ: Qu α
Initialwert:
Stacks
Typ: St α
Initialwert:
für alle Werte der freien Variablen zu True auswerten
Axiome spezifizieren:
I
I
Signatur und Semantik
Axiome müssen gelten
I
10 [26]
::
Test auf Leer:
St α→ Bool
Last in first out (LIFO).
isEmpty
:: Qu α→ Bool
First in first out (FIFO)
Gleiche Signatur, unterscheidliche Semantik.
11 [26]
Eigenschaften von Stack
12 [26]
Eigenschaften von Queue
First in first out (FIFO):
Last in first out (LIFO):
f i r s t ( enq a empty ) == a
t o p ( push a s ) == a
n o t ( i s E m p t y q ) =⇒ f i r s t ( enq a q ) == f i r s t q
pop ( push a s ) == s
deq ( enq a empty ) == empty
i s E m p t y empty
n o t ( i s E m p t y q ) =⇒ deq ( enq a q ) = enq a ( deq q )
n o t ( i s E m p t y ( push a s ) )
i s E m p t y ( empty )
push a s /= empty
n o t ( i s E m p t y ( enq a q ) )
enq a q /= empty
13 [26]
Implementation von Stack: Liste
Implementation von Queue
Sehr einfach: ein Stack ist eine Liste
data S t a c k a= S t a c k [ a ]
14 [26]
I
Mit einer Liste?
d e r i v i n g ( Show , Eq )
I
empty =
Stack
Problem: am Ende anfügen oder abnehmen ist teuer.
[]
I
Deshalb zwei Listen:
push a ( S t a c k s ) = S t a c k ( a : s )
top
( Stack
pop
::
[])
= e r r o r " S t a c k : t o p on empty s t a c k "
Stack a → Stack a
15 [26]
I
Erste Liste: zu entnehmende Elemente
I
Zweite Liste: hinzugefügte Elemente rückwärts
I
Invariante: erste Liste leer gdw. Queue leer
16 [26]
Repräsentation von Queue
Operation
empty
enq 9
enq 4
enq 7
deq
enq 5
enq 3
deq
deq
deq
deq
deq
Resultat
9
4
7
5
3
error
Implementation
Queue
I
Repräsentation
([], [])
([9], [])
([9], [4])
([9], [7, 4])
([4, 7], [])
([4, 7], [5])
([4, 7], [3, 5])
([7], [3, 5])
([5, 3], [])
([3], [])
([], [])
([], [])
9
4 →9
7 →4 →9
7 →4
5 →7 →4
3 →5 →7 →4
3 →5 →7
3 →5
3
Datentyp:
data Qu α = Qu [ α ] [ α ]
I
Leere Schlange: alles leer
empty = Qu [ ]
I
[]
Invariante: erste Liste leer gdw. Queue leer
i s E m p t y (Qu x s _) = n u l l x s
I
Erstes Element steht vorne in erster Liste
f i r s t (Qu [ ] _) = e r r o r " Queue : f i r s t o f empty Q"
f i r s t (Qu ( x : x s ) _) = x
17 [26]
Implementation
I
18 [26]
Axiome als Eigenschaften
Bei enq und deq Invariante prüfen
I
Axiome können getestet oder bewiesen werden
I
Tests finden Fehler, Beweis zeigt Korrektheit
I
Arten von Tests:
enq x (Qu x s y s ) = c h e c k x s ( x : y s )
deq (Qu [ ] _ )
= e r r o r " Queue : deq o f empty Q"
deq (Qu (_ : x s ) y s ) = c h e c k x s y s
I
I
Prüfung der Invariante nach dem Einfügen und Entnehmen
I
Unit tests (JUnit, HUnit)
I
Black Box vs.White Box
I
Zufallsbasiertes Testen
check garantiert Invariante
c h e c k :: [ α ] → [ α ] → Qu α
c h e c k [ ] y s = Qu ( r e v e r s e y s )
c h e c k x s y s = Qu x s y s
[]
I
Funktionale Programme eignen sich sehr gut zum Testen
19 [26]
Zufallsbasiertes Testen in Haskell
I
Werkzeug: QuickCheck
I
Zufällige Werte einsetzen, Auswertung auf True prüfen
I
Polymorphe Variablen nicht testbar
I
Deshalb Typvariablen instantiieren
I
I
Typ muss genug Element haben (hier Int)
I
Durch Signatur Typinstanz erzwingen
20 [26]
Axiome mit QuickCheck testen
I
Für das Lesen:
prop_read_empty :: I n t → Bool
prop_read_empty a =
l o o k u p ( empty :: Map I n t I n t ) a == N o t h i n g
p r o p _ r e a d _ w r i t e :: Map I n t I n t → I n t → I n t → Bool
p r o p _ r e a d _ w r i t e s a v=
l o o k u p ( i n s e r t s a v ) a == J u s t v
Freie Variablen der Eigenschaft werden Parameter der Testfunktion
I
Hier: Eigenschaften direkt als Haskell-Prädikate
I
Es werden N Zufallswerte generiert und getestet (N = 100)
22 [26]
21 [26]
Axiome mit QuickCheck testen
I
Axiome mit QuickCheck testen
I
Bedingte Eigenschaft in quickCheck:
I
A =⇒B mit A, B Eigenschaften
I
Typ ist Property
I
Es werden solange Zufallswerte generiert, bis N die Vorbedingung
erfüllende gefunden und getestet wurden, andere werden ignoriert.
Schreiben:
p r o p _ w r i t e _ w r i t e :: Map I n t I n t → I n t → I n t → I n t → Bool
prop_write_write s a v w =
i n s e r t ( i n s e r t s a v ) a w == i n s e r t s a w
I
p r o p _ w r i t e _ o t h e r ::
Map I n t I n t → I n t → I n t → I n t → I n t → P r o p e r t y
prop_write_other s a v b w =
a /= b =⇒ i n s e r t ( i n s e r t s a v ) b w ==
i n s e r t ( i n s e r t s b w) a v
p r o p _ r e a d _ w r i t e _ o t h e r ::
Map I n t I n t → I n t → I n t → I n t → P r o p e r t y
p r o p _ r e a d _ w r i t e _ o t h e r s a v b=
a /= b =⇒ l o o k u p ( i n s e r t s a v ) b == l o o k u p s b
I
23 [26]
Schreiben an anderer Stelle:
Test benötigt Gleichheit auf Map a b
24 [26]
Zufallswerte selbst erzeugen
I
I
Zusammenfassung
Problem: Zufällige Werte von selbstdefinierten Datentypen
I
Signatur: Typ und Operationen eines ADT
I
Gleichverteiltheit nicht immer erwünscht (e.g. [a])
I
Axiome: über Typen formulierte Eigenschaften
I
Konstruktion nicht immer offensichtlich (e.g. Map)
I
Spezifikation = Signatur + Axiome
In QuickCheck:
I
I
I
Typklasse class Arbitrary a für Zufallswerte
Eigene Instanziierung kann Verteilung und Konstruktion berücksichtigen
E.g. Konstruktion einer Map:
I
I
Interface zwischen Implementierung und Nutzung
I
Testen zur Erhöhung der Konfidenz und zum Fehlerfinden
I
Beweisen der Korrektheit
QuickCheck:
I
Zufällige Länge, dann aus sovielen zufälligen Werten Map konstruieren
I
Freie Variablen der Eigenschaften werden Parameter der Testfunktion
I
Zufallswerte in Haskell?
I
=⇒ für bedingte Eigenschaften
25 [26]
26 [26]
Herunterladen