ws 2002/2003 programmierung 1 - repetitorium andreas augustin und marc wagner

18
Programmierung 1 - Repetitorium WS 2002/2003 Programmierung 1 - Repetitorium Andreas Augustin und Marc Wagner Homepage: http://info1.marcwagner.info

Upload: jennifer-stone

Post on 30-Dec-2015

28 views

Category:

Documents


1 download

DESCRIPTION

WS 2002/2003 Programmierung 1 - Repetitorium Andreas Augustin und Marc Wagner Homepage: http://info1.marcwagner.info. Montag, den 07.04.03 Kapitel 3 Typen und Prozeduren. 3.1 Typen und Typdisziplin. - PowerPoint PPT Presentation

TRANSCRIPT

Programmierung 1 - Repetitorium

WS 2002/2003

Programmierung 1 - Repetitorium

Andreas Augustin und Marc Wagner

Homepage: http://info1.marcwagner.info

Programmierung 1 - Repetitorium

Montag, den 07.04.03

Kapitel 3

Typen und Prozeduren

Programmierung 1 - Repetitorium

3.1 Typen und Typdisziplin

int { 1 , 2 , ... } real { 3.4 , 5.0 , ... } unit { ( ) } bool { true , false }

Die Typdisziplin einer Programmiersprache sorgt dafür,dass auf Werte nur solche Operationen angewendet werden können,die die Werte richtig interpretieren.

Eine vereinfachte Typdisziplin von SML ist die monomorphe Typdisziplin :

1. Jeder Konstante und jedem gebundenen Bezeichner ist genau ein Typzugeordnet.

2. Jedem Operationssymbol sind endlich viele Typen zugeordnet.

3. Für Operationsausdrücke wird die folgende Typregel verwendet :

a1 : t1 : t1 t2→t a2 : t2

a1 a2 : t

4. Für Konditionale wird die folgende Typregel verwendet :

a1 : bool a2 : t a3 : t

if a1 then a2 else a3 : t

Programmierung 1 - Repetitorium

3.1 Typen und Typdisziplin

5. Für Tupelausdrücke wird die folgende Typregel verwendet :

a1 : t1 ... an : tn

(a1,...,an) : t1...tn

6. Für Prozeduranwendungen wird die folgende Typregel verwendet :

p : t1 → t2 a : t1

p a : t2

7. Die obigen Regeln sorgen dafür, dass jedem zulässigen Ausdruckgenau ein Typ zugeordnet werden kann.

8. Wenn die Auswertung eines Audrucks, dem der Typ t zugeordnet wurde,einen Wert liefert, handelt es sich immer um einen Wert des Typs t.Diese wichtige Eigenschaft der Typdisziplin nennt sich Typsicherheit.

Typen können nicht mit der Menge ihrer Werte identifiziert werden.Typen legen zusätzlich eine Interpretation für ihre Werte fest.

Programmierung 1 - Repetitorium

3.2 Prozeduren sind Werte

Prozeduren können als Komponenten von Tupeln und als Argumenteund Ergebnisse von Prozeduren vorkommen.

Prozeduren mit prozeduralen Argumenten oder Ergebnissen bezeichnetman als höherstufige Prozeduren.

Prozeduren lassen sich mit speziellen Ausdrücken (Abstraktionen) beschreiben :

fn (x:int, y:int) => x*y

Abstraktionen sind Ausdrücke, die zu Prozeduren auswerten.Eine Abstraktion beschreibt eine Prozedur ohne ihr einen Namen zu geben.

val produkt = fn (x:int, y:int) => x*y

Rekursive Prozeduren kann man wegen der Selbstreferenz nicht unmittelbarmit Abstraktionen beschreiben.

val rec f = fn n:int => if n<1 then 1 else f(n-1)

Eine Abkürzung dafür ist : fun f (n:int) = if n<1 then 1 else f(n-1)

Programmierung 1 - Repetitorium

3.2 Prozeduren sind Werte

Beispiel für den Nutzen prozeduraler Argumente :

n

i

ifnfsum1

)(),(

val rec sum = fn (f:int->int, n:int) => if n<1 then 0 else sum(f, n-1) + f(n)

fun sum (f:int->int, n:int) = if n<1 then 0 else sum(f, n-1) + f(n)

Die Summe der ersten 10 Quadratzahlen erhält man hiermit :

sum (fn i:int => i*i, 10)

Programmierung 1 - Repetitorium

3.3 Kartesische und kaskadierte Prozeduren

Prozeduren, deren Argumenttyp ein Produkttyp t1...tn ist, sind kartesisch.

plus : int * int -> intfun plus (x:int, y:int) = x+y Alternativ : val plus = fn (x:int, y:int) => x+yplus (3,4)

Prozeduren, deren Ergebnistyp ein Pfeiltyp t1 → t2 ist, sind kaskadiert.

plus : int -> int -> intfun plus (x:int) (y:int) = x+yAlternativ : val plus = fn x:int => fn y:int => x+yplus 3 4

Der Typkonstruktor -> klammert nach rechts.

int -> int -> int int -> ( int -> int )

Prozeduranwendungen klammern nach links.

plus 3 4 ( plus 3 ) 4

Programmierung 1 - Repetitorium

3.4 Polymorphe Prozeduren

Prozeduren, die auf mehr als einen Typ anwendbar sind, sind polymorph.

Sei X eine Menge, f X → X und n 0. Wir definieren fn X → X rekursiv :

fn(x) = if n = 0 then x else fn-1(f(x))

Wir deklarieren jetzt eine kaskadierte Funktion iter, die für einen beliebigenTyp t anwendbar ist und die Funktion f n-mal hintereinander auf x anwendet :

fun iter (f:‘a->‘a) (n:int) (x:‘a) = if n<1 then x else iter f (n-1) (f x)

Typschema : val iter : (‘a -> ‘a) -> int -> ‘a -> ‘a

Hierbei ist ‘a (gesprochen : alpha) eine sogenannte Typvariable.

Anwendungsbeispiele von iter :

iter (fn x:int => x*x) 4 2

iter (fn x:real => x*x) 5 2.0

iter (fn x:bool => not x) 3 true

Instanz des Typschemas :

(int -> int) -> int -> int -> int

(real -> real) -> int -> real -> real

(bool -> bool) -> int -> bool -> bool

Programmierung 1 - Repetitorium

3.4 Polymorphe Prozeduren

Jedes Typschema hat unendlich viele Instanzen. (aufgrund des Pfeiles)

Ein Bezeichner heißt polymorph, wenn ihm ein Typschema zugeordnet ist.

Ein Ausdruck heißt polymorph, wenn man ihm mehrere Typ zuordnen kann.

Ein Ausdruck heißt expansiv, wenn er eine Prozedur- oder eine Operations-Anwendung enthält, die nicht innerhalb einer Abstraktion steht.

Man unterscheidet folgende Arten von Deklarationen :

1. Monomorphe Deklaration : Wenn a ein monomorpher Ausdruck mit demTyp t ist, wird x monomorph mit dem Typ t typisiert.Beispiel : fun inc x = x+1 val inc : int -> int

2. Polymorphe Deklaration : Wenn a ein polymorpher Ausdruck ist, der nichtexpansiv ist, wird x polymorph mit dem Typschema typisiert, dass alle Typenvon a beschreibt.Beispiel : fun id (x:‘a) = x val id : ‘a -> ‘a

Programmierung 1 - Repetitorium

3.4 Polymorphe Prozeduren

3. Ambige Deklaration : Wenn a ein polymorpher und expansiver Ausdruck ist,wird x monomorph mit einem der dem Ausdruck a zugeordneten Typentypisiert. Dabei wird der Typ so gewählt, dass er mit den nachfolgendenVerwendungen des Bezeichners x verträglich ist (wenn möglich).Beispiel : val f = id id val f : ‘b -> ‘b (Warning!)

Bei rekursiven Deklarationen und Prozedurdeklarationen kann der ambige Fallnicht auftreten ! (rechte Seite ist Abstraktion und somit nicht expansiv)

fun f (x:int) = f x val f : int -> ‘a

Der Bezeichner f wird polymorph mit dem Schema ‘a (int -> ‘a)typisiert, da als Ergebnistyp von f jeder Typ zulässig ist.

Programmierung 1 - Repetitorium

3.5 Typinferenz

Das automatische Herleiten von fehlenden Typconstraints nennt man Typinferenz.

Typinferenz berechnet immer die allgemeinsten Typconstraints.

Bei überladenen Operationssymbolen gibt die Typinferenz int den Vorzug.

fun sum f n = if n<1 then 0 else sum f (n-1) + f nval sum : (int -> int) -> int -> int

fun plus (x,y) = x+yval plus : int * int -> int

Durch die Angabe von expliziten Typconstraints können bei größeren ProgrammenTypfehler schneller lokalisiert werden und diese Fehler direkt bei der Deklarationdiagnostiziert werden.

fun f(x,y) = (2*x,y)val f : int * ‘a -> int * ‘a

Programmierung 1 - Repetitorium

3.6 Op-Ausdrücke

Op-Ausdrücke sind Abkürzungen für Abstraktionen, die Operationen alsKartesische Prozeduren zur Verfügung stellen.

op+ fn (x,y) => x+y

op< fn (x,y) => x<y

op= fn (x,y) => x=y

op div fn (x,y) => x div y

op ~ fn x => ~x

Da die meisten Operationssymbole überladen sind, ist das Weglassen derTypconstraints für die Argumentvariablen der Abstraktionen wesentlich.

Programmierung 1 - Repetitorium

3.7 Typen und Gleichheit

Typen, für deren werte ein Test auf Gleichheit mit = möglich ist, heißenTypen mit Gleichheit.

Die Typen int, bool und unit sind Beispiele für Typen mit Gleichheit.

Dagegen sind die Pfeiltypen t1 → t2 Typen ohne Gleichheit.

Auf Produkttypen t1 ... tn ist der Gleichheitstest genau dann zulässig,wenn er auf allen Komponenten t1 , ... , tn zulässig ist.

Um die Unterscheidung zwischen Typen mit und ohne Gleichheit in Typschemataausdrücken zu können, gibt es zwei Arten von Typvariablen :

Typvariablen mit nur einem Hochkomma ‘a für beliebige Typen

Typvariablen mit zwei Hochkommas ‘‘a nur für Typen mit Gleichheit

Programmierung 1 - Repetitorium

3.8 Bezeichnerbindung

1. Dynamische Bezeichnerbindungen (bei Ausführung einer Phrase) :

val f = fn x => x*xf 5

Die Ausführung der Anwendung bindet die Argumentvariable x dynamischan die Zahl 5.

2. Statische Bezeichnerbindungen (bei semantischer Analyse einer Phrase) :

val f = fn x => x*x

Die Analyse der Deklaration bindet den Bezeichner f statisch an den Typ int -> int und den Bezeichner x statisch an int.

3. Lexikalische Bezeichnerbindungen :

Lexikalische Bindungen beschreiben den strukturellen Rahmen fürstatische und dynamische Bindungen.

Programmierung 1 - Repetitorium

3.8 Bezeichnerbindung

Für das Auftreten (Vorkommen) von Bezeichnern gibt es zwei Möglichkeiten :definierend und benutzend

Definierende Auftreten führen eine Bindung ein.

Benutzende Auftreten benutzen eine bestehende Bindung.

Benutzende Auftreten, die innerhalb der betrachteten Phrase lexikalischungebunden sind, werden als freie Auftreten bezeichnet.

fn x => fn y => z x (y x)

Die überstrichenen Bezeichner sind definierende Auftreten,die anderen sind benutzende Auftreten.Der Bezeichner z ist hier frei vorkommend, da er keinem definierenden Vorkommenvon z innerhalb der betrachteten Phrase zugeordnet werden kann.

Programmierung 1 - Repetitorium

3.8 Bezeichnerbindung

Die lexikalischen Bindungen lassen sich auch textuell darstellen.

Alle Bezeichnerauftreten einer Bindungsgruppe werden dabei mit demselbenIndex markiert. Dagegen bekommen freie Bezeichner keinen Index.Mehrere definierende Auftreten desselben Bezeichner werden mit verschiedenenIndizes versehen.

fn x => fn y => (fn y => (fn x => z x y) x) y

fn x1 => fn y1 => (fn y2 => (fn x2 => z x2 y2) x1) y1

Lexikalische Bindungen textuell dargestellt :

Diese Phrase lässt sich nun wie folgt bereinigen (konsistente Umbenennung) :

fn x => fn y => (fn u => (fn v => z v u) x) y

Bei einer Abstraktion fn x => a ist der Gültigkeitsbereich des definierendenAuftretens von x der Ausdruck a. Alle benutzenden Auftreten von x, die lexikalischan dieses definierende Auftreten von x gebunden sind, müssen sich innerhalb desAusdrucks a befinden.

Programmierung 1 - Repetitorium

3.9 Prozeduren und Auswertungsprotokolle

Wenn ein Ausdruck keine freien Bezeichner enthält, heißt er geschlossen,sonst nennt man ihn offen.

Offene Ausdrücke sind unvollständige Beschreibungen, die nur im Kontext vonexternen Bezeichnerbindungen interpretiert werden können.

val x = 1fun inc y = x+y

liefert die dynamischen Bindungen

x → 1inc → fn y => 1+y

Eine Redeklaration des Bezeichners x hat damit keine Auswirkung auf die bereitsBerechnete Prozedur inc :

val x = 5

liefert die dynamischen Bindungen

x → 5inc → fn y => 1+y (die Bindung von inc ist also unverändert)

Programmierung 1 - Repetitorium

3.9 Prozeduren und Auswertungsprotokolle

fun f x y = if x = 0 then y else y + f (x-1) y

führt folgende dynamische Bindung ein :

f → rec f => fn x => fn y => if x=0 then y else y + f (x-1) y

Das Auswertungsprotokoll für den Ausdruck f 1 5 ergibt :

f 1 5 → 1 5 (wobei die rekursive Abstraktion ist) → (fn y => if 1=0 then y else y + (1-1) y) 5→ if 1=0 then 5 else 5 + (1-1) 5→ if false then 5 else 5 + (1-1) 5→ 5 + (1-1) 5→ 5 + 0 5→ 5 + (fn y => if 0=0 then y else y + (0-1) y) 5→ 5 + (if 0=0 then 5 else 5 + (0-1) 5)→ 5 + (if true then 5 else 5 + (0-1) 5)→ 5 + 5→ 10