Programmierung 1 - Repetitorium
WS 2002/2003
Programmierung 1 - Repetitorium
Andreas Augustin und Marc Wagner
Homepage: http://info1.marcwagner.info
Programmierung 1 - Repetitorium
Mittwoch, den 09.04.03
Kapitel 6
Konstruktortypen und Ausnahmen
Programmierung 1 - Repetitorium
6.1 Varianten und Konstruktoren
Ziel: Darstellung der drei geometrischen Formen Kreis, Quadrat und Dreieckals mathematische Objekte
Das Paar < 1 , r > stellt einen Kreis mit Radius r dar.
Das Paar < 2 , a > stellt ein Quadrat mit der Seitenlänge a dar.
Das Paar < 3 , < a , b , c > > stellt ein Dreieck mit den Seitenlängen a,b,c dar.
Die erste Komponente des Paares bezeichnet man als Variantennummer.Sie gibt die Form des geometrischen Objekts an.
Die zweite Komponente des Paares bezeichnet man als Datum.Sie spezifiziert die Dimensionen des geometrischen Objekts.
datatype shape = Circle of real | Square of real | Triangle of real * real * real
Programmierung 1 - Repetitorium
6.1 Varianten und Konstruktoren
Der Datentyp shape liefert uns jetzt die Konstruktoren Circle, Square und Triangle.
Circle 4.0 Square 3.0 Triangle ( 4.0 , 3.0 , 5.0 )
Circle Square Triangle
4.0 3.0 4.0 3.0 5.0
Berechnung des Flächeninhalts :
fun area (Circle r) = Math.pi * r * r | area (Square a) = a * a | area (Triangle (a,b,c)) = let val s = (a+b+c)/2.0 in Math.sqrt(s*(s-a)*(s-b)*(s-c)) end
Programmierung 1 - Repetitorium
6.1 Varianten und Konstruktoren
Die Prozedur area ist mit drei Regeln definiert, die jeweils für eine der dreiVarianten von shape zuständig sind.
Die Muster der Regeln haben die Form einer Konstruktoranwendung.
Die Deklaration von Konstruktoren ermöglicht es, die verschiedenen Varianteneines Konstruktortyps durch frei gewählte Namen zu bezeichnen.
Konvention:
Konstruktoren = Bezeichner mit Großbuchstaben beginnend
Typen und Werte = Bezeichner mit Kleinbuchstaben beginnend
Programmierung 1 - Repetitorium
6.2 Enumerationstyp
datatype day = Monday | Tuesday | Wednesday | Thursday | Friday | Saturday | Sunday
Die Werte des Typs day werden durch nullstellige Konstruktoren beschrieben,die wie Konstanten verwendet werden können.
fun weekend Saturday = true | weekend Sunday = true | weekend _ = false
Typ: weekend : day → bool
map weekend [ Monday , Wednesday , Friday , Saturday, Sunday ] = [ false , false , false , true, true ]
Typen, die nur mit Hilfe von nullstelligen Konstruktoren definiert sind,werden als Enumerationstyp bezeichnet.
vordeklarierter Enumerationstyp: datatype order = LESS | EQUAL | GREATER
Programmierung 1 - Repetitorium
6.3 Typsynonyme
type point = real * real
point ist hierbei kein neuer Typ, sondern eine neue Bezeichnung für einenbereits existierenden Typ.
sinnvolle Verwendungen :
datatype object = Circle of point * real | Triangle of point * point * point
Wir können auch einen neuen Typ einführen :
datatype point = P of real * real
P ( 2.0 , 3.0 ) : point
fun mirror ( P ( x , y ) ) = P ( ~x , y )
Programmierung 1 - Repetitorium
6.4 Ausnahmen
Ausnahmen sind Werte des Typs exn.
Neue Ausnahmen deklariert man mithilfe von exception.
exception Newexception Newer of int
New sowie Newer sind Ausnahmekonstruktoren, diese können wie normaleKonstruktoren verwendet werden.
Zusätzlich kann man mit Ausdrücken der Form
raise e
die Ausnahme e werfen (e vom Typ exn)
raise Newer 6!Uncaught exception: Newer 6
Raise-Ausdrücke liefern keinen Wert, daher können sie jeden Typ annehmen.
Programmierung 1 - Repetitorium
6.4 Ausnahmen
Geworfene Ausnahmen können mithilfe von Handle-Ausdrücken gefangen werden.
( raise New ) handle New => ( )( raise Newer 7 ) handle Newer x => 7fun test f = f() handle Newer x => x | Overflow => ~1
Beim Programmieren mit Ausnahmen sind manchmal Sequenzialisierungen( e1 ; ... ; en) hilfreich.
Auswertung einer Sequenz:Alle Teilausdrücke e1 , ... , en von links nach recht auswerten.Bei Terminierung aller Ausdrücke, liefert die Sequenz den Wert des letztenTeilausdrucks en.
(e1,...,en) = let val _ = e1
... val _ = en-1
in en
end
Programmierung 1 - Repetitorium
6.5 Arithmetische Ausdrücke
type var = int (Variablen als ganze Zahlen)
datatype exp = C of int | V of var | A of exp*exp | M of exp*exp
Jede Ausdrucksform ( Konstante, Variable, Addition, Multiplikation ) wird durcheinen entsprechenden Konstruktor realisiert.
Darstellung der rekursiven Struktur von exp:
exp
int var
C V
MA
Programmierung 1 - Repetitorium
6.5 Arithmetische Ausdrücke
( 2 x + y ) * ( x + 3 )
val e = M ( A ( M ( C 2 , V 1 ) , V 2 ) , A ( V 1 , C 3 ) )
M
A A
M V V C
C V 2 1 3
2 1
Um den Ausdruck auszuwerten, benötigen wir eine Umgebung,die den Variablen x und y Werte zuweist. { x → 5 , y → 3 }
val env = fn 1 => 5 | 2 => 3 | _ => raise Unbound
datatype exp = C of int| V of var| A of exp*exp| M of exp*exp
Programmierung 1 - Repetitorium
6.5 Arithmetische Ausdrücke
Unser Ziel : die Evaluierungsprozedur eval : exp → env → int
fun eval ( C c ) _ = c | eval ( V v ) env = env v | eval ( A (e,e‘) ) env = eval e env + eval e‘ env | eval ( M (e,e‘) env = eval e env * eval e‘ env
Programmierung 1 - Repetitorium
6.6 Optionen
datatype ‘a option = NONE | SOME of ‘a
NONE ist die uneingelöste Option, SOME ist die eingelöste Option.
fun get xs n = SOME (List.nth(xs,n)) handle Subscript => NONE
liefert das n-te Element einer Liste als eingelöste Option, wenn es existiert.
get [3,4,5] 2 = SOME 5get [3,4,5] 3 = NONE
fun valOf (SOME x) = x | valOf NONE = raise Option.Option
erlaubt bequemen Zugriff auf eingelöste Optionen
fun isSome NONE = false | isSome (SOME _) = true
testet, ob es sich um eine eingelöste Option handelt
Programmierung 1 - Repetitorium
6.7 Case-Ausdrücke und abgeleitete Formen
fun sign x = case Int.compare (x,0) of LESS => ~1 | EQUAL => 0 | GREATER => 1
case e of M1 => e1 | ... | Mn => en = ( fn M1 => e1 | ... | Mn => en ) e
if e1 then e2 else e3 = (fn true => e2 | false => e3) e1
Programmierung 1 - Repetitorium
6.8 Bäume informell und formal
Größe des Baumes = Anzahl der Knoten des Baumes
Pfad = Verbindung zwischen 2 bel. Knoten eines Baumes
Länge des Pfades = Anzahl der Kanten des Pfades
Tiefe des Knotens = Länge des Pfades von der Wurzel zu den Knoten
Tiefe des Baumes = Max. Tiefe seiner Knoten
3
14
2 7
2
1 3 0
Wurzel
Kante
Knoten
Marke
1.Nachfolger
2.Nachfolger 3.Nachfolger
Vorgänger
Blatt
Programmierung 1 - Repetitorium
6.8 Bäume informell und formal
Eigenschaften von Bäumen :
1. Zwischen 2 Knoten eines Baumes existiert immer genau ein Pfad.
2. Die Wurzel eines Baumes hat keinen Vorgänger und alle anderen Knotenhaben genau einen Vorgänger.
Tiefe eines Knotens = Länge seiner Adresse
u Adresse des Knotens ⇒ u@[n] Adresse seines n-ten Nachfolgers
3
0 4 1
1 2 7 7
2 7 7
[ ]
[1] [2] [3]
[1,1] [3,1] [3,2] [3,3]
[1,1,1] [1,1,2] [1,1,3]
Programmierung 1 - Repetitorium
6.8 Bäume informell und formal
Bäume mit genau einem Knoten heißen atomar.
Bäume mit mind. zwei Knoten heißen zusammenhängend.
Die Blätter eines Baumes sind alle Knoten ohne Nachfolger.
Jeder Baum hat genau eine Wurzel, mindestens ein Blatt und mind. einen Knoten.
Ein Baum ist aus seinem Kopf (Marke der Wurzel) und seinen Unterbäumen(Teilbäume der Nachfolger der Wurzel) zusammengesetzt. ( x , [ t1 , ... , tn ] )
1
2 7 7
( 1 , [ ( 2 , [ ] ) , ( 7 , [ ] ) , ( 7 , [ ] ) ] )
Ein Baum heißt linear gdw. jeder Knoten höchstens einen Nachfolger hat.
Ein Baum heißt binär gdw. jeder Knoten außer den Blättern genau zweiNachfolger hat.
Ein Baum heißt balanciert gdw. alle Blätter gleiche Tiefe haben.
Jeder atomare Baum ist linear, binär und balanciert.
Programmierung 1 - Repetitorium
6.9 Ein ausführbares Modell für Bäume
datatype ‘a tree = T of ‘a * ( ‘a tree list )
1
2 7 7
T ( 1 , [ T ( 2 , [ ] ) , T ( 7 , [ ] ) , T ( 7 , [ ] ) ] )
fun head (T(x,_)) = x
fun dst (T(_,ts)) n = List.nth(ts,n-1)
liefert den Kopf des Baumes
liefert den n-ten Unterbaum von t
fun atomic (T(_,ts)) = null ts
testet, ob ein Baum atomar ist
Programmierung 1 - Repetitorium
6.9 Ein ausführbares Modell für Bäume
fun subtree t nil = t | subtree t (n::ns) = subtree (dst t n) ns
fun node t ns = (subtree t ns; true) handle Subscript => false
fun leaf t ns = atomic (subtree t ns) handle Subscript => false
testet für einen Baum, ob es sich bei einer Liste um einen Knoten desBaumes handelt
testet für einen Baum, ob es sich bei einer Liste um ein Blatt des Baumes handelt
fun label t ns = head (subtree t ns)
liefert die Marke eines Knotens
liefert zu einem Baum und einer Liste den zugeordneten Teilbaum
fun pred t nil = raise Subscript | pred t ns = (subtree t ns; rev(tl(rev ns)))
liefert zu einem Baum und einem Knoten den Vorgänger des Knotens
Programmierung 1 - Repetitorium
6.9 Ein ausführbares Modell für Bäume
fun succ t ns n = let val ns‘ = ns@[n] in subtree t ns‘; ns‘ end
fun size (T(_,ts)) = foldl op+ 1 (map size ts)
fun depth (T(_,ts)) = 1 + foldl Int.max -1 (map depth ts)
liefert die Größe eines Baumes ( = 1 + Summe der Größen seiner Unterbäume )
liefert die Tiefe eines Baumes ( = 1 + max. Tiefe seiner Unterbäume )
liefert zu einem Baum, einem Knoten und einer Zahl n den n-ten Nachfolger desKnotens
Programmierung 1 - Repetitorium
6.10 Test auf Balanciertheit
Ein Baum ist genau dann balanciert, wenn für jeden seiner Teilbäume t gilt,dass alle seine Unterbäume die gleiche Höhe haben bzw. alle Blätter diegleiche Tiefe haben.
fun balanced t = let exception Unbalanced fun depthb (T(_,nil)) = 0 | depthb (T(_,t::tr)) = 1 + foldl forward (depth t) tr and forward (t,n) = if depthb t = n then n else raise Unbalanced in (depthb t; true) handle Unbalanced => false end
depthb und forward sind verschränkt rekursiv, daher ist eine Deklarationmit and erforderlich.
Programmierung 1 - Repetitorium
6.11 Linearisation und Projektionen
Eine Liste heißt Linearisierung eines Baumes, wenn sie genau die Knoten desBaumes enthält (ohne Doppelauftreten), und wenn sie die Knoten jedesTeilbaumes als Segment enthält.
Die Projektion einer Liste von Knoten erhält man, indem man jeden Knotendurch seine Marke ersetzt.
Präfixlinearisierung :
1. Für jeden Teilbaum gilt : Die Wurzel erscheint vor den Knoten derUnterbäume.
2. Für jeden Teilbaum mit mindestens zwei Unterbäumen gilt :Die Knoten der Unterbäume erscheinen in der Reihenfolge der Unterbäume.
fun project t nss = map (label t) nss
fun pre (T(x,ts)) = x :: List.concat (map pre ts)
Programmierung 1 - Repetitorium
6.11 Linearisation und Projektionen
Postfixlinearisierung :
fun post (T(x,ts)) = List.concat (map post ts) @ [x]
Analog zur Präfixlinearisierung, nur mit dem Unterschied, dass die Wurzeleines Teilbaums diesmal nach dem Knoten seiner Unterbäume erscheint.
3
2 7 7
0 4 1
5
Präfix : [ 3 , 0 , 5 , 4 , 1 , 2 , 7 , 7 ]
Postfix : [ 5 , 0 , 4 , 2 , 7 , 7 , 1 , 3 ]
Top Related