• Keine Ergebnisse gefunden

Rekursive Datentypen

N/A
N/A
Protected

Academic year: 2022

Aktie "Rekursive Datentypen"

Copied!
4
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

Praktische Informatik 3: Funktionale Programmierung Vorlesung 3 vom 28.10.2014: Rekursive Datentypen

Christoph Lüth Universität Bremen Wintersemester 2014/15

Rev. 2746 1 [32]

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 [32]

Inhalt

I RekursiveDatentypen

I RekursiveDefinition

I . . . und wozu sie nützlich sind

I Rekursive Datentypen in anderen Sprachen

I Fallbeispiel: Labyrinthe

3 [32]

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 [32]

Rekursive Datentypen

I Der definierte TypTkannrechtsbenutzt werden.

I Rekursive Datentypen sindunendlich.

I Entsprichtinduktiver Definition

I ModelliertAggregation(Sammlung von Objekten)

I Funktionen werden durchRekursiondefiniert.

5 [32]

Algebraische Datentypen: Nomenklatur

Gegeben Definition dataT = C1t1,1. . .t1,k1

. . .

| Cntn,1. . .tn,kn I CisindKonstruktoren

IImmervordefiniert

I Selektorensind Funktionen seli,j: seli,j(Citi,1. . .ti,ki) = ti,j IPartiell, linksinvers zu Konstruktor

IKönnenvordefiniert werden (erweiterte Syntax derdataDeklaration) I Diskriminatorensind Funktionen disi:

disi :: T→Bool disi(Ci. . .) = True disi_ = False

IDefinitionsbereichsbereich des Selektors seli INievordefiniert

6 [32]

Uncle Bob’s Auld Time Grocery Shoppe Revisited

I Das Lager für Bob’s Shoppe:

I ist entweder leer,

I oder es enthält einen Artikel und Menge, und weiteres.

data Lager = LeeresLager

| Lager A r t i k e l Menge Lager

7 [32]

Suchen im Lager

I Rekursive Suche (erste Version):

suche :: A r t i k e l→ Lager→Menge suche art LeeresLager = ???

I Modellierung desResultats:

data Resultat = Gefunden Menge | NichtGefunden I Damit rekursiveSuche:

suche :: A r t i k e l→ Lager→ Resultat suche art (Lager l a r t m l )

| art == l a r t = Gefunden m

| otherwise = suche art l suche art LeeresLager = NichtGefunden

8 [32]

(2)

Einlagern

I Mengen sollen aggregiert werden, d.h. 35l Milch und 20l Milch werden zu 55l Milch.

I Dazu Hilfsfunktion:

addiere (Stueck i ) (Stueck j )= Stueck ( i+ j ) addiere (Gramm g) (Gramm h) = Gramm (g+ h) addiere ( L i t e r l ) ( L i t e r m) = L i t e r ( l+ m)

addiere m n = er ro r (" addiere : ␣"++ show m++ "␣und␣"++ show n) I Damit einlagern:

einlagern :: A r t i k e l→Menge→Lager→ Lager einlagern a m LeeresLager = Lager a m LeeresLager einlagern a m (Lager a l ml l )

| a == a l = Lager a ( addiere m ml) l

| otherwise = Lager a l ml ( einlagern a m l ) I Problem: Falsche Mengenangaben

I z.B.einlagern Eier ( Liter 3.0) l

9 [32]

Einlagern (verbessert)

I Eigentliche Funktioneinlagernwird alslokale Funktionversteckt, und nur mit gültiger Mengenangabe aufgerufen:

einlagern :: A r t i k e l→Menge→ Lager→ Lager einlagern a m l =

let einlagern ’ a m LeeresLager = Lager a m LeeresLager einlagern ’ a m (Lager a l ml l )

| a == a l = Lager a ( addiere m ml) l

| otherwise = Lager a l ml ( einlagern ’ a m l ) in case p r e i s a mof

Ungueltig → l _→ einlagern ’ a m l

10 [32]

Einkaufen und bezahlen

I Wir brauchen einenEinkausfwagen:

data Einkaufswagen = LeererWagen

| Einkauf A r t i k e l Menge Einkaufswagen I Artikel einkaufen:

einkauf :: A r t i k e l→Menge→Einkaufswagen→ Einkaufswagen einkauf a m e =

case p r e i s a mof Ungueltig → e _→ Einkauf a m e I Gesamtsumme berechnen:

kasse :: Einkaufswagen→ Int kasse LeererWagen = 0

kasse ( Einkauf a m e) = cent a m+ kasse e

11 [32]

Beispiel: Kassenbon

kassenbon :: Einkaufswagen→ String 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

12 [32]

Kassenbon: Implementation

I Kernfunktion:

a r t i k e l :: Einkaufswagen→ String a r t i k e l LeererWagen = ""

a r t i k e l ( Einkauf a m e) = formatL 20 (show a) ++ formatR 7 (menge m) ++

formatR 10 (showEuro ( cent a m)) ++ "\n"++ a r t i k e l e

I Hilfsfunktionen:

formatL :: Int→ String→ String

13 [32]

Rekursive Typen in Java

I Nachbildung durch Klassen, z.B. für Listen:

class L i s t {

public L i s t (Object el , L i s t t l ) { this. elem= e l ;

this. next= t l ; }

public Object elem ; public L i s t next ; I Länge (iterativ):

int length () { int i= 0;

for ( L i s t cur=this; cur !=null; cur= cur . next ) i ++ ;

return i ; }

14 [32]

Rekursive Typen in C

I C: Produkte, Aufzählungen, keine rekursiven Typen I Rekursion durchZeiger

typedef struct l i s t _ t { void ∗elem ; struct l i s t _ t ∗next ; }∗l i s t ;

I Konstruktorennutzerimplementiert l i s t cons(void ∗hd , l i s t t l ) { l i s t l ;

i f (( l= ( l i s t ) malloc (sizeof(struct l i s t _ t )))== NULL) { p r i n t f ( "Out␣of␣memory\n" ) ; e x i t (−1);

}

l→elem= hd ; l→ next= t l ; return l ;

}

15 [32]

Fallbeispiel: Zyklische Datenstrukturen

Quelle: docs.gimp.org

16 [32]

(3)

Modellierung eines Labyrinths

I EingerichtetesLabyrinth ist entweder

I eine Sackgasse,

I ein Weg, oder

I eine Abzweigung in zwei Richtungen.

dataLab = Dead Id

| Pass Id Lab

| TJnc Id Lab Lab

I Ferner benötigt: eindeutigeBezeichnerder Knoten type Id = Integer

17 [32]

Ein Labyrinth (zyklenfrei)

0 1 2 3 4

5?

6 7?

8 6

-9 6

10?

-11 12 -13 6

14?

15 16

? -17

6

18 -19

20 6

21 22? -23

6 24?

18 [32]

Traversion des Labyrinths

I Ziel:Pfadzu einem gegebenZielfinden

I BenötigtPfadeundTraversion data Path = Cons Id Path

| Mt data Trav = Succ Path

| F a i l

19 [32]

Traversionsstrategie

I Geht vonzyklenfreienLabyrinth aus

I An jedem Knoten prüfen, ob Ziel erreicht, ansonsten

Ian SackgasseFail

Ian Passagen weiterlaufen

Ian Kreuzungen Auswahl treffen I Erfordert Propagation vonFail:

cons :: Id→ Trav→Trav s e l e c t :: Trav→ Trav→Trav

20 [32]

Zyklenfreie Traversion

traverse1 :: Id→ Lab→ Trav traverse1 t l

| nid l == t = Succ (Cons ( nid l ) Mt)

| otherwise =case l of Dead _→ F a i l

Pass i n→ cons i ( traverse1 t n)

TJnc i n m→ s e l e c t (cons i ( traverse1 t n)) (cons i ( traverse1 t m))

21 [32]

Traversion mit Zyklen

I VeränderteStrategie: Pfad bis hierher übergeben

IPfad musshintenerweitert werden.

I WennaktuellerKnoten in bisherigen Pfadenthaltenist,Fail I Ansonsten wie oben

I Neue Hilfsfunktionen:

contains :: Id→ Path→Bool cat :: Path→Path→ Path snoc :: Path→ Id→Path

22 [32]

Traversion mit Zyklen

traverse2 :: Id→ Lab→ Path→Trav traverse2 t l p

| nid l == t = Succ (snoc p ( nid l ))

| contains ( nid l ) p = F a i l

| otherwise =case l of Dead _→ F a i l

Pass i n→ traverse2 t n (snoc p i )

TJnc i n m→ s e l e c t ( traverse2 t n (snoc p i )) ( traverse2 t m (snoc p i ))

23 [32]

Ein Labyrinth (mit Zyklen)

0 1 2 3 4

5?

∗ 6 7? 8

6 -9

6

10?

-11 12 -13 6

14?

15

∗6 16?

-17 6

18 -19

20 6

21 22

? -23

6 24

?

24 [32]

(4)

Ungerichtete Labyrinth

I In einemungerichtetenLabyrinth haben Passagen keine Richtung.

I Sackgassen haben einen Nachbarn,

I eine Passage hat zwei Nachbarn,

I und eine Abzweigung drei Nachbarn.

dataLab = Dead Id Lab

| Pass Id Lab Lab

| TJnc Id Lab Lab Lab

I Andere Datentypen und Hilfsfunktionen bleiben (mutatis mutandis) I Jedes nicht-leere ungerichtete Labyrinth hatZyklen.

I Invariante(nicht durch Typ garantiert)

25 [32]

Traversion in ungerichteten Labyrinthen

I Traversionsfunktion wie vorher traverse3 :: Id→Lab→Path→ Trav traverse3 t l p

| nid l == t = Succ (snoc p ( nid l ))

| contains ( nid l ) p = F a i l

| otherwise =case l of

Dead i n → traverse3 t n (snoc p i )

Pass i n m→ s e l e c t ( traverse3 t n (snoc p i )) ( traverse3 t m (snoc p i )) TJnc i n m k → s e l e c t ( traverse3 t n (snoc p i ))

( s e l e c t ( traverse3 t m (snoc p i )) ( traverse3 t k (snoc p i )))

26 [32]

Zusammenfassung Labyrinth

I Labyrinth−→GraphoderBaum I In Haskell: gleicher Datentyp I Referenzen nichtexplizitin Haskell

I KeineundefiniertenReferenzen (erhöhteProgrammsicherheit)

I KeineGleichheitauf Referenzen

I Gleichheit istimmerstrukturell (oderselbstdefiniert)

27 [32]

Beispiel: Zeichenketten selbstgemacht

I EineZeichenketteist

Ientwederleer(das leere Wort)

Ioder einZeichencund eine weitereZeichenkettexs dataMyString = Empty

| Cons Char MyString

I LineareRekursion

IGenau ein rekursiver Aufruf

28 [32]

Rekursive Definition

I Typisches Muster:Fallunterscheidung

I EinFallproKonstruktor

I Hier:

I LeereZeichenkette

I NichtleereZeichenkette

29 [32]

Funktionen auf Zeichenketten

I Länge:

len :: MyString→ Int

len Empty = 0

len (Cons c s t r ) = 1+ len s t r I Verkettung:

cat :: MyString→MyString→ MyString cat Empty t = t

cat (Cons c s ) t = Cons c ( cat s t ) I Umkehrung:

rev :: MyString→MyString rev Empty = Empty

rev (Cons c t ) = cat ( rev t ) (Cons c Empty)

30 [32]

Was haben wir gesehen?

I StrukturellähnlicheTypen:

I Einkaufswagen,Path,MyString(Listen-ähnlich)

I Resultat,Preis,Trav(Punktierte Typen) I ÄhnlicheFunktionendarauf

I Besser:eineTypdefinition mit Funktionen, instantiierung zu verschiedenen Typen

Nächste Vorlesung

31 [32]

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)

32 [32]

Referenzen

ÄHNLICHE DOKUMENTE

I Für funktionale Programme: rekursiv definierte Funktionen.. Äquivalenz von operationaler und

Ein abstrakter Datentyp (ADT) besteht aus einem (oder mehreren) Typen und Operationen darauf, mit folgenden Eigenschaften:. I Werte des Typen können nur über die

Praktische Informatik 3: Funktionale Programmierung Vorlesung 10 vom 20.12.2016: Aktionen und ZuständeI. Christoph Lüth Universität Bremen

Praktische Informatik 3: Funktionale Programmierung Vorlesung 2 vom 21.10.2014: Funktionen und Datentypen..

contains :: Id→ Path→ Bool cat :: Path→ Path→ Path snoc :: Path→ Id → Path..

I Werte des Typen können nur über die bereitgestellten Operationen erzeugt werden. I Eigenschaften von Werten des Typen werden nur über die bereitgestellten

konstanter Aufwand ←→ beliebige Genauigkeit, wachsender Aufwand Haskell bietet die Auswahl:. I Int - ganze Zahlen als Maschinenworte (≥

Praktische Informatik 3: Funktionale Programmierung Vorlesung 3 vom 30.10.2012: Rekursive Datentypen..