Praktische Informatik 3: Funktionale Programmierung Vorlesung 3 vom 30.10.2012: Rekursive Datentypen
Christoph Lüth Universität Bremen Wintersemester 2012/13
Rev. 1935 1 [27]
Fahrplan
I Teil I: Funktionale Programmierung im Kleinen
IEinführung
IFunktionen und Datentypen
IRekursive Datentypen
ITypvariablen und Polymorphie
IFunktionen höherer Ordnung I
IFunktionen höherer Ordnung II
ITypinferenz
I Teil II: Funktionale Programmierung im Großen I Teil III: Funktionale Programmierung im richtigen Leben
2 [27]
Inhalt
I RekursiveDatentypen
I RekursiveDefinition
I . . . und wozu sie nützlich sind
I Rekursive Datentypen in anderen Sprachen
I Fallbeispiel: Labyrinthe
3 [27]
Der Allgemeine Fall: Algebraische Datentypen
Definition einesalgebraischen DatentypenT:
data T= C1t1,1. . .t1,k1
. . .
| Cntn,1. . .tn,kn
I KonstruktorenC1, . . . ,Cnsinddisjunkt:
Cix1. . .xn=Cjy1. . .ym−→i=j I Konstruktorensindinjektiv:
C x1. . .xn=C y1. . .yn−→xi=yi I Konstruktorenerzeugenden Datentyp:
∀x∈T.x=Ciy1. . .ym Diese Eigenschaften machenFallunterscheidungmöglich.
Heute:Rekursion
4 [27]
Rekursive Datentypen
I Der definierte TypTkannrechtsbenutzt werden.
I Rekursive Datentypen sindunendlich
I Entsprichtinduktiver Definition
I ModelliertAggregation(Sammlung von Objekten)
I Funktionen werden durchRekursiondefiniert
5 [27]
Algebraische Datentypen: Nomenklatur
Gegeben Definition data T= C1t1,1. . .t1,k1
. . .
| Cntn,1. . .tn,kn
I CisindKonstruktoren(vordefiniert) I Selektorensind Funktionenseli,j:
seli,j(Citi,1. . .ti,ki) =ti,j IPartiell, linksinvers zu Konstruktor
IKönnen vordefiniert werden (erweiterte Syntax derdataDeklaration) I Diskriminatorensind Funktionendisi:
disi ::T→Bool
disi(Ci. . .) =True
disi_ =False
IDefinitionsbereichsbereich des Selektorsseli INie vordefiniert
6 [27]
Uncle Bob’s Auld Time Grocery Shoppe Revisited
I Ein Lager für Bob’s Shoppe:
I entweder leer
I oder es enthält Artikel und Menge, und weiteres data L a g e r = L e e r e s L a g e r
| L a g e r A r t i k e l Menge L a g e r
7 [27]
Suchen im Lager
I Rekursive Suche:
s u c h e :: A r t i k e l→ L a g e r→ R e s u l t a t s u c h e a r t ( L a g e r l a r t m l )
| a r t == l a r t = G e f u n d e n m
| o t h e r w i s e = s u c h e a r t l
s u c h e a r t L e e r e s L a g e r = N i c h t g e f u n d e n
I Resultat:
data R e s u l t a t = G e f u n d e n Menge | N i c h t g e f u n d e n
8 [27]
Einlagern
I Mengen sollen aggregiert werden, e.g. 35l Milch und 20l Milch werden 55l Milch
e i n l a g e r n :: A r t i k e l→ Menge→ L a g e r→ L a g e r e i n l a g e r n a m l =
l e t h i n e i n a m L e e r e s L a g e r = L a g e r a m L e e r e s L a g e r h i n e i n a m ( L a g e r a l ml l )
| a == a l = L a g e r a ( a d d i e r e m ml ) l
| o t h e r w i s e = L a g e r a l ml ( h i n e i n a m l ) i n c a s e p r e i s a m o f
U n g u e l t i g → l _ → h i n e i n a m l
a d d i e r e ( S t u e c k i ) ( S t u e c k j )= S t u e c k ( i+ j ) a d d i e r e ( Gramm g ) ( Gramm h ) =Gramm ( g+h ) a d d i e r e ( L i t e r l ) ( L i t e r m) = L i t e r ( l+m)
a d d i e r e m n = e r r o r ( " a d d i e r e : ␣ "++ show m++ " ␣ und ␣ "++ show n )
9 [27]
Einkaufen und bezahlen
I Artikel einkaufen:
e i n k a u f :: A r t i k e l→ Menge→ E i n k a u f s w a g e n→ E i n k a u f s w a g e n e i n k a u f a m e =
c a s e p r e i s a m o f U n g u e l t i g → e _ → E i n k a u f a m e
I Gesamtsumme berechnen:
k a s s e :: E i n k a u f s w a g e n→ I n t k a s s e L e e r e r W a g e n = 0
k a s s e ( E i n k a u f a m e ) = c e n t a m+ k a s s e e
10 [27]
Beispiel: Kassenbon
k a s s e n b o n :: E i n k a u f s w a g e n→ S t r i n g Ausgabe:
Bob’s Aulde Grocery Shoppe
Artikel Menge Preis
---
Schinken 50 g. 0.99 EU
Milch Bio 1.0 l. 1.19 EU
Schinken 50 g. 0.99 EU
Apfel Boskoop 3 St 1.65 EU
=====================================
Summe: 4.82 EU
Unveränderlicher Kopf
Ausgabe von Artikel und Mange (rekur- siv)
Ausgabe vonkasse
11 [27]
Kassenbon: Implementation
I Kernfunktion:
a r t i k e l :: E i n k a u f s w a g e n→ S t r i n g a r t i k e l L e e r e r W a g e n = " "
a r t i k e l ( E i n k a u f a m e ) = f o r m a t L 20 ( show a ) ++
f o r m a t R 7 ( menge m) ++
f o r m a t R 10 ( showEuro ( c e n t a m) ) ++ " \n "++
a r t i k e l e I Hilfsfunktionen:
f o r m a t L :: I n t→ S t r i n g→ S t r i n g f o r m a t R :: I n t→ S t r i n g→ S t r i n g showEuro :: I n t→ S t r i n g
12 [27]
Rekursive Typen in Java
I Nachbildung durch Klassen, z.B. für Listen:
c l a s s L i s t {
p u b l i c L i s t ( O b j e c t e l , L i s t t l ) { t h i s. e l e m= e l ;
t h i s. n e x t= t l ; }
p u b l i c O b j e c t e l e m ; p u b l i c L i s t n e x t ; I Länge (iterativ):
i n t l e n g t h ( ) { i n t i= 0 ;
f o r ( L i s t c u r= t h i s; c u r != n u l l; c u r= c u r . n e x t ) i++;
r e t u r n i ; }
13 [27]
Rekursive Typen in C
I C: Produkte, Aufzählungen, keine rekursiven Typen I Rekursion durchZeiger
t y p e d e f s t r u c t l i s t _ t {
v o i d ∗e l e m ;
s t r u c t l i s t _ t ∗n e x t ; } ∗l i s t ;
I Konstruktorennutzerimplementiert l i s t c o n s (v o i d ∗hd , l i s t t l ) { l i s t 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→ e l e m= hd ; l→ n e x t= t l ; r e t u r n l ;
}
14 [27]
Fallbeispiel: Zyklische Datenstrukturen
Quelle: docs.gimp.org
15 [27]
Modellierung des Labyrinths
I Ein Labyrinth ist entweder
Ieine Sackgasse,
Iein Weg, oder
Ieine Abzweigung in zwei Richtungen.
data Lab =Dead I d
| P a s s I d Lab
| TJnc I d Lab Lab
I Ferner benötigt: eindeutigeBezeichnerder Knoten type I d = I n t
16 [27]
Traversion des Labyrinths
I Ziel:Pfadzu einem gegebenZielfinden
I BenötigtPfadeund eine Strategie
data Path = Cons I d Path
| Mt
data Trav = Succ Path
| F a i l
17 [27]
Traversionsstrategie
I An jedem Knoten prüfen, ob Ziel erreicht, ansonsten
Ian SackgasseFail
Ian Passagen weiterlaufen
Ian Kreuzungen Auswahl treffen I erfordert Propagation vonFail:
c o n s :: I d→ Trav→ Trav s e l e c t :: Trav→ Trav→ Trav
I Geht vonzyklenfreienLabyrinth aus
18 [27]
Zyklenfreie Traversion
t r a v e r s e 1 :: I d→ Lab→ Trav t r a v e r s e 1 t ( Dead i )
| i == t = Succ ( Cons i Mt )
| o t h e r w i s e = F a i l t r a v e r s e 1 t ( P a s s i l )
| t == i = Succ ( Cons i Mt )
| o t h e r w i s e = c o n s i ( t r a v e r s e 1 t l ) t r a v e r s e 1 t ( TJnc i l m)
| t == i = Succ ( Cons i Mt )
| o t h e r w i s e = s e l e c t ( c o n s i ( t r a v e r s e 1 t l ) ) ( c o n s i ( t r a v e r s e 1 t m) )
19 [27]
Traversion mit Zyklen
t r a v e r s e 2 :: I d→ Lab→ Path→ Trav t r a v e r s e 2 t ( Dead i ) p
| i == t = Succ ( r e v ( Cons i p ) )
| o t h e r w i s e = F a i l t r a v e r s e 2 t ( P a s s i l ) p
| c o n t a i n s i p = F a i l
| t == i = Succ ( r e v ( Cons i p ) )
| o t h e r w i s e = t r a v e r s e 2 t l ( Cons i p ) t r a v e r s e 2 t ( TJnc i l m) p
| c o n t a i n s i p = F a i l
| t == i = Succ ( r e v ( Cons i p ) )
| o t h e r w i s e = s e l e c t ( t r a v e r s e 2 t l ( Cons i p ) ) ( t r a v e r s e 2 t m ( Cons i p ) )
20 [27]
Traversion mit Zyklen
I VeränderteStrategie: Pfad bis hierher übergeben
I WennaktuellerKnoten in bisherigen Pfadenthaltenist,Fail I Ansonsten wie oben
I Neue Hilfsfunktionen
c o n t a i n s :: I d→ Path→ B o o l r e v :: Path→ Path
21 [27]
Zusammenfassung Labyrinth
I Labyrinth−→GraphoderBaum I In Haskell: gleicher Datentyp I Referenzen nichtexplizitin Haskell
IKeineundefiniertenReferenzen (erhöhteProgrammsicherheit)
IKeineGleichheitauf Referenzen
IGleichheit istimmerstrukturell (oderselbstdefiniert)
22 [27]
Beispiel: Zeichenketten selbstgemacht
I EineZeichenketteist
I entwederleer(das leere Wort)
I oder einZeichencund eine weitereZeichenkettexs data M y S t r i n g = Empty
| Cons Char M y S t r i n g
I LineareRekursion
I Genau ein rekursiver Aufruf
23 [27]
Rekursive Definition
I Typisches Muster:Fallunterscheidung
IEinFallproKonstruktor
I Hier:
ILeereZeichenkette
INichtleereZeichenkette
24 [27]
Funktionen auf Zeichenketten
I Länge:
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 I Verkettung:
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 ) 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 )
25 [27]
Was haben wir gesehen?
I StrukturellähnlicheTypen:
IEinkaufswagen,Path,MyString(Listen-ähnlich)
IResultat,Preis,Trav(Punktierte Typen) I ÄhnlicheFunktionendarauf
I Besser:eineTypdefinition mit Funktionen, instantiierung zu verschiedenen Typen
Nächste Vorlesung
26 [27]
Zusammenfassung
I Datentypen könnenrekursivsein
I Rekursive Datentypen sindunendlich(induktiv) I Funktionen werdenrekursivdefiniert
I Fallbeispiele: Einkaufen in Bob’s Shoppe, Labyrinthtraversion I Viele strukturell ähnliche Typen
I NächsteWoche: Abstraktion über Typen (Polymorphie)
27 [27]