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

Werbung
Fahrplan
I
Praktische Informatik 3: Einführung in die Funktionale
Programmierung
Vorlesung vom 10.11.2010: Rekursive Datentypen
Christoph Lüth & Dennis Walter
Teil I: Funktionale Programmierung im Kleinen
I
Einführung
I
Funktionen und Datentypen
I
Rekursive Datentypen
I
Typvariablen und Polymorphie
I
Funktionen höherer Ordnung
I
Typinferenz
Universität Bremen
Wintersemester 2010/11
Rev. 1152
I
Teil II: Funktionale Programmierung im Großen
I
Teil III: Funktionale Programmierung im richtigen Leben
2 [23]
1 [23]
Inhalt
I
I
Der Allgemeine Fall: Algebraische Datentypen
Definition eines algebraischen Datentypen T:
data T = C1 t1,1 . . . t1,k1
...
| Cn tn,1 . . . tn,kn
Rekursive Datentypen
I
Formen der Rekursion
I
Rekursive Definition
I
Rekursive Datentypen in anderen Sprachen
I
Konstruktoren C1 , . . . , Cn sind disjunkt:
Ci x1 . . . xn = Cj y1 . . . ym −→ i = j
I
Konstruktoren sind injektiv:
C x1 . . . xn = C y1 . . . yn −→ xi = yi
I
Konstruktoren erzeugen den Datentyp:
∀x ∈ T . x = Ci y1 . . . ym
Induktiver Beweis
I
Schluss vom kleineren aufs größere
Diese Eigenschaften machen Fallunterscheidung möglich.
3 [23]
Rekursive Datentypen
4 [23]
Induktive Definitionen
I
I
Der definierte Typ T kann rechts benutzt werden.
I
Rekursive Datentypen sind unendlich
I
Entspricht induktiver Definition
I
Beispiel natürliche Zahlen: Peano-Axiome
I
0∈N
I
wenn n ∈ N, dann S n ∈ N
I
S injektiv und S n 6= 0
I
Induktionsprinzip: φ(0), φ(x ) −→ φ(S x ), dann ∀n ∈ N.φ(n)
Induktionsprinzip erlaubt Definition rekursiver Funktionen:
n+0 = n
n + S m = S(n + m)
5 [23]
Natürliche Zahlen in Haskell
6 [23]
Beispiel: Zeichenketten selbstgemacht
I
Direkte Übersetzung der Peano-Axiome
I
Der Datentyp:
I
entweder leer (das leere Wort )
data Nat = Z er o
| S Nat
I
oder ein Zeichen c und eine weitere Zeichenkette xs
I
I
Eine Zeichenkette ist
data M y S t r i n g = Empty
| Cons Char M y S t r i n g
Rekursive Funktionsdefinition:
add :: Nat → Nat → Nat
add n Z e ro = n
add n ( S m) = S ( add n m)
I
Lineare Rekursion
I
7 [23]
Genau ein rekursiver Aufruf
8 [23]
Rekursive Definition
Funktionen auf Zeichenketten
I
I
l e n :: M y S t r i n g → I n t
l e n Empty
= 0
l e n ( Cons c s t r ) = 1+ l e n s t r
Typisches Muster: Fallunterscheidung
I
Ein Fall pro Konstruktor
I
I
Länge:
c a t :: M y S t r i n g → M y S t r i n g → M y S t r i n g
c a t Empty t
= t
c a t ( Cons c s ) t = Cons c ( c a t s t )
Hier:
I
Leere Zeichenkette
I
Nichtleere Zeichenkette
Verkettung:
I
Umkehrung:
r e v :: M y S t r i n g → M y S t r i n g
r e v Empty
= Empty
r e v ( Cons c t ) = c a t ( r e v t ) ( Cons c Empty )
9 [23]
Baumartige Rekursion: Binäre Bäume
I
Wechselseitige Rekursion: Variadische Bäume
Datentyp:
data BTree = MtBTree
| BNode I n t BTree BTree
I
10 [23]
I
data VTree = MtVTree
| VNode S t r i n g VNodes
Funktion, bsp. Höhe:
data VNodes = MtVNodes
| VMore VTree VNodes
h e i g h t :: BTree → I n t
h e i g h t MtBTree = 0
h e i g h t ( BNode j l r ) = max ( h e i g h t l ) ( h e i g h t r )+ 1
I
Variable Anzahl Kinderknoten
I
Baumartige Rekursion
I
VNodes: Liste von Kinderbäumen
Doppelter rekursiver Aufruf
11 [23]
Wechselseitige Rekursion: Variadische Bäume
I
I
12 [23]
Rekursive Typen in anderen Sprachen
Hauptfunktion:
I
Standard ML: gleich
c o u n t :: VTree → I n t
c o u n t MtVTree = 0
c o u n t ( VNode _ n s ) = 1+ c o u n t _ n o d e s n s
I
Lisp: keine Typen, aber alles ist eine S-Expression
Hilfsfunktion:
I
data SExpr = Quote Atom | Cons SExpr SExpr
c o u n t _ n o d e s :: VNodes → I n t
c o u n t _ n o d e s MtVNodes = 0
c o u n t _ n o d e s ( VMore t ns )= c o u n t t+ c o u n t _ n o d e s n s
Python, Ruby:
I
Listen (Sequenzen) vordefiniert
I
Keine anderen Typen
13 [23]
Rekursive Typen in Java
I
I
14 [23]
Rekursive Typen in C
Nachbildung durch Klassen, z.B. für Listen:
I
class List {
public L i s t ( Object el , L i s t t l ) {
t h i s . elem= e l ;
t h i s . n e x t= t l ;
}
p u b l i c O b j e c t elem ;
public L i s t
next ;
I
C: Produkte, Aufzählungen, keine rekursiven Typen
Rekursion durch Zeiger
typedef s t r u c t l i s t _ t {
void
∗ elem ;
struct l i s t _ t ∗ next ;
} ∗list ;
I
Länge (iterativ):
int length () {
i n t i= 0 ;
f o r ( L i s t c u r= t h i s ; c u r 6= n u l l ; c u r= c u r . n e x t )
i ++ ;
return i ;
}
15 [23]
Konstruktoren nutzerimplementiert
l i s t c o n s ( v o i d ∗hd , l i s t t l )
{ list l ;
i f ( ( l= ( l i s t ) m a l l o c ( s i z e o f ( s t r u c t l i s t _ t ) ) )== NULL) {
p r i n t f ( " Out o f memory \n " ) ; e x i t ( −1);
}
l → elem= hd ; l → n e x t= t l ;
return l ;
}
16 [23]
Rekursive Definition, induktiver Beweis
I
Beweis durch vollständige Induktion
Definition durch Rekursion
I
Basisfall (leere Zeichenkette)
I
Rekursion (nicht-leere Zeichenkette)
Zu zeigen:
Für alle natürlichen Zahlen x gilt P(x ).
Beweis:
r e v :: M y S t r i n g → M y S t r i n g
r e v Empty
= Empty
r e v ( Cons c t ) = c a t ( r e v t ) ( Cons c Empty )
I
I
I
Induktionsbasis: P(0)
I
Induktionsschritt:
Reduktion der Eingabe (vom größeren aufs kleinere)
Beweis durch Induktion
I
I
Induktionsvoraussetzung P(x )
I
zu zeigen P(x + 1)
Schluß vom kleineren aufs größere
17 [23]
Beweis durch strukturelle Induktion (Zeichenketten)
18 [23]
Beweis durch strukturelle Induktion (Allgemein)
Zu zeigen:
Zu zeigen:
Für alle (endlichen) Zeichenketten xs gilt P(xs)
Für alle x in T gilt P(x )
Beweis:
Beweis:
I
Induktionsbasis: P()
I
Induktionsschritt:
I
I
Induktionsvoraussetzung P(xs)
I
zu zeigen P(x xs)
Für jeden Konstruktor Ci :
I
Voraussetzung: für alle ti,j gilt P(ti,j )
I
zu zeigen P(Ci ti,1 . . . ti,ki )
19 [23]
Beispielbeweise
20 [23]
Spezifikation und Korrektheit
I
Die ersten n Zeichen einer Zeichenkette (n ≥ 0)
takeN :: I n t → M y S t r i n g → M y S t r i n g
takeN n Empty = Empty
takeN n ( Cons c s ) = i f n == 0 then Empty
e l s e Cons c ( takeN ( n−1) s )
len s ≥ 0
len (cat s t) = len s + len t
len (rev s) = len s
(1)
I
Zeichenkette ohne die ersten n Zeichen (n ≥ 0)
dropN :: I n t → M y S t r i n g → M y S t r i n g
dropN n Empty
= Empty
dropN n ( Cons c s ) = i f n == 0 then Cons c s
e l s e dropN ( n− 1 ) s
(2)
(3)
I
Eigenschaften:
len (takeN n s) ≤ n
(4)
len (dropN n s) ≥ len s − n
(5)
cat (takeN n s) (dropN n s) = s
21 [23]
Zusammenfassung
I
Datentypen können rekursiv sein
I
Rekursive Datentypen sind unendlich (induktiv)
I
Funktionen werden rekursiv definiert
I
Formen der Rekursion: linear, baumartig, wechselseitig
I
Rekursive Definition ermöglicht induktiven Beweis
I
Nächste Woche: Abstraktion über Typen (Polymorphie)
23 [23]
(6)
22 [23]
Herunterladen