• Keine Ergebnisse gefunden

Funktionales Programmieren Teil 5 Carl Philipp Reh

N/A
N/A
Protected

Academic year: 2021

Aktie "Funktionales Programmieren Teil 5 Carl Philipp Reh"

Copied!
13
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

Funktionales Programmieren

Teil 5

Carl Philipp Reh

Universit¨at Siegen

29. Mai 2020

(2)

Auswertung

Wir betrachten folgende Beispielfunktion s q u a r e :: Int - > Int

s q u a r e x = x * x

In welcher Reihenfolge wird folgender Ausdruck ausgewertet?

s q u a r e (2 + 3)

Option 1 (Call by Value): Wertezuerstden Parameter 2 + 3 aus und ersetze dann die Definition von s q u a r e:

s q u a r e (2 + 3) = s q u a r e 5 = 5 * 5 = 25 Option 2 (Call by Name): Ersetzezuerstdie Definition von s q u a r e und werte den Parameter aus, wenn n¨otig:

s q u a r e (2 + 3) = (2 + 3) * (2 + 3)

= 5 * (2 + 3) = 5 * 5 = 25

(3)

Auswertung

Nachteil bei Call by Name: Wir werten 2 * 3 zweimal aus.

Vorteil: Man kann sich m¨oglicherweise die Auswertung des Parameters ganz sparen.

Haskell verwendet eine Variation von Call by Name, die Call by Need oder Lazy Evaluation genannt wird. Bei dieser werden alle Teilausdr¨ucke, die aus demselben Ausdruck

”entstanden“ sind, nur einmal ausgewertet:

s q u a r e (2 + 3) = (2 + 3) * (2 + 3)

= 5 * 5 = 25 Hier werden beide Teilausdr¨ucke2 * 3

”auf einmal“ ausgewertet.

Eine formale Beschreibung dieses

”schrittweisen Auswertens“ nennt man auchoperationelle Semantik. Diese ist vor allem daf¨ur

n¨utzlich, einen Compiler zu implementieren, aber weniger n¨utzlich, um ¨uber das

”Verhalten“ eines Programms zu argumentieren.

(4)

Denotationelle Semantik

Bei denotationeller Semantik geht es darum, Ausdr¨ucken

mathematische Funktionen zuzuordnen. Beispielsweise w¨urden wir gerne der Funktion s q u a r e die mathematische Funktion

JsquareK:Z→Zmit JsquareK(x) =x2 zuordnen.

Dass Int einen endlichen Wertebereich hat, ignorieren wir an der Stelle. Ein anderes Problem ist aber, dass es auch divergierende Ausdr¨ucke in Haskell gibt. Zum Beispiel liefert folgende Funktion nie einen Wert:

u n d e f i n e d :: a - > a

u n d e f i n e d x = u n d e f i n e d x

Also liefert auch s q u a r e ( u n d e f i n e d 2) nie einen Wert.

(5)

Undefinierte Argumente

Betrachten wir folgende Definition von and: and :: B o o l - > B o o l - > B o o l and x y = c a s e x of

F a l s e - > F a l s e T r u e - > y

Was passiert bei folgendem Programm?

and ( u n d e f i n e d T r u e ) T r u e

Da c a s e auf u n d e f i n e d T r u e angewandt wird, terminiert das Programm nicht. Im Gegensatz dazu gilt

and F a l s e ( u n d e f i n e d T r u e ) = F a l s e

weil and sofort F a l s e liefert, wenn das erste Argument F a l s e ist, ohne das zweite Argument auszuwerten.

(6)

Semantik von square

Wir ben¨otigen f¨ur die Semantik von Funktionen also sowohl f¨ur die Parameter als auch f¨ur die Ergebnisse noch den speziellen Wert

”undefiniert“, den wir mit ⊥(Bottom) bezeichnen. Sei

Z =Z∪ {⊥}. F¨ur die Semantik von s q u a r e k¨onnen wir also JsquareK:Z →Z nehmen mit

JsquareK(x) =

(⊥ falls x=⊥, x2 falls x6=⊥.

Was allerdings denotationelle Semantik aufw¨andig macht, ist die Tatsache, dass wir Funktionen rekursiv definieren k¨onnen und dass Haskell Funktionen h¨oherer Ordnung hat.

Wir werden stetige Funktionen ben¨otigen, um rekursiv definierten Funktionen eine Semantik zuordnen zu k¨onnen, was etwas Vorbereitung braucht.

(7)

Partielle Ordnungen

Ein Paar (D,vD), wobeiD eine Menge ist und vD ⊆D×D, heißtpartielle Ordnung, wennvD folgendes erf¨ullt:

I Reflexivit¨at: F¨ur alle d ∈D gilt d vD d.

I Antisymmetrie: F¨ur alled,d0∈D gilt: Wenn d vD d0 und d0 vD d, dann giltd =d0. Alternativ: Es gibt keine d 6=d0 ∈D mitd vD d0 und d0 vD d.

I Transitivit¨at: F¨ur alle d,d0,d00∈D gilt: Wenn d vD d0 und d0 vD d00, dann giltd vD d00.

Wir werden oft einfach nurD statt (D,vD) und vstatt vD schreiben, wennvD aus dem Kontext bekannt ist.

Alle Ordnungen, die wir betrachten, haben die Intuition, dass d vD d0 gilt, wennd

”weniger definiert“ ist alsd0.

(8)

Flache Ordnungen

F¨ur eine Menge D ist die flache Ordnung(D,vD) definiert als D =D] {⊥D}und d vDd0 genau dann, wennd =⊥D oder d =d0. Dies definiert eine partielle Ordnung.

Beispiel: (Z,vZ) ist die Ordnung, bei der gilt, dass ⊥ZvZd f¨ur alled ∈Z. In diesem Sinne ist also⊥Z

”undefinierter“ als alle ganzen Zahlen, aber keine ganze Zahl ist

”undefinierter“ als eine andere. Grafisch:

. . . −2 −1 0 1 2 . . .

Z

Wir schreiben oft einfach nur⊥statt⊥D, wennD aus dem Kontext bekannt ist.

(9)

Produkt-Ordnung

Zun ≥0 partiellen Ordnungen (D1,vD1), . . . ,(Dn,vDn) definieren wir dieProdukt-Ordnung(D1× · · · ×Dn,vD1×···×Dn) wie folgt: Es gilt (d1, . . . ,dn)vD1×···×Dn (d10, . . . ,dn0) genau dann, wenn

di vDi di0 f¨ur alle 1≤i ≤n.

Als Beispiel seiZ2 ={0,1} und wir betrachten die partielle Ordnung ((Z2)×(Z2),v(Z

2)×(Z2)). Grafisch:

(0,0) (0,1) (1,0) (1,1)

(0,⊥) (⊥,0) (⊥,1) (1,⊥)

(⊥,⊥)

(10)

Die Produkt-Ordnung ist eine partielle Ordnung

Lemma 1

Die Produkt-Ordnung ist eine partielle Ordnung.

Beweis.

Reflexivit¨at: Sei (d1, . . . ,dn)∈D1× · · · ×Dn. Es gilt di vDi di f¨ur alle 1≤i ≤n, weilvDi reflexiv ist. Also folgt

(d1, . . . ,dn)v(d1, . . . ,dn).

Antisymmetrie: Wenn (d1, . . . ,dn)v(d10, . . . ,dn0) und

(d10, . . . ,dn0)v(d1, . . . ,dn), dann gilt di vDi di0 und di0 vDi di f¨ur alle 1≤i ≤n. Weil vDi antisymmetrisch ist, giltdi =di0 f¨ur alle 1≤i ≤n. Also folgt (d1, . . . ,dn) = (d10, . . . ,dn0).

Transitivit¨at: Wenn (d1, . . . ,dn)v(d10, . . . ,dn0) und

(d10, . . . ,dn0)v(d100, . . . ,dn00), dann giltdi vDi di0 und di0 vDi di00 f¨ur alle 1≤i ≤n. Wegen Transitivit¨at von vDi gilt auchdi vDi di00 f¨ur alle 1≤i ≤n. Also folgt (d1, . . . ,dn)v(d100, . . . ,dn00).

(11)

Ordnung auf Funktionen

SeienD eine Menge und (E,vE) eine partielle Ordnung. Wir definieren die partielle Ordnung (D →E,vD→E) wie folgt: F¨ur f,f0:D →E giltf vD→E f0 genau dann, wenn f¨ur alled ∈D gilt, dassf(d)vE f0(d).

In gewissem Sinne ist dies analog zu Tupeln, wenn man sich eine FunktionD →E als ein|D|-stelliges Tupel mit Komponenten aus E vorstellt.|D|kann allerdings unendlich sein.

Lemma 2

(D→E,vD→E)ist eine partielle Ordnung.

Beweis.

Ubung.¨

(12)

Ordnung auf Funktionen

SeiZ1 ={0}. Wir betrachten die Funktionen (Z1)→(Z1), f¨ur die wir folgende Ordnung erhalten:

(⊥ → ⊥, 0→ ⊥)

(⊥ → ⊥, 0→0) (⊥ →0, 0→ ⊥)

(⊥ →0, 0→0)

Die Schreibweise (⊥ →x, 0→y) bedeutet, dass ⊥auf x und 0 aufy abgebildet werden.

Die Funktion (⊥ → ⊥, 0→ ⊥) ist also

”am wenigsten definiert“

und die Funktion (⊥ →0, 0→0) ist

”am meisten definiert“.

(13)

Monotone Funktionen

Seien (D,vD) und (E,vE) partielle Ordnungen. Eine Funktion f:D→E heißtmonoton, wenn f¨ur alle d,d0 ∈D mitd vD d0 gilt, dassf(d)vE f(d0).

Die Intuition ist, dass ein Argument, das

”mehr definiert“ ist, nicht zu einem Ergebnis f¨uhren kann, das

”weniger“ definiert ist.

In unserem vorherigen Beispiel ist die Funktionf mitf(⊥) = 0 undf(0) =⊥also nicht monoton, weil ⊥ v0 gilt, aber f(⊥) = 06v ⊥=f(0). Diese Funktion l¨asst sich auch nicht in Haskell implementieren, weil die Implementierung testen m¨usste, ob ihr Argument divergiert.

Die anderen drei Funktionen sind monoton, da

I Identit¨atenf(x) =x monoton sind, denn es gilt f¨ur alle d vd0, dass f(d) =d vd0=f(d0), und

I konstante Funktionen f(x) =c monoton sind, denn es gilt f¨ur alle d vd0, dassf(d) =c vc =f(d0).

Referenzen

ÄHNLICHE DOKUMENTE

The justices submitted, to their own judgment, the more general question of whether the automatic preference of the father’s surname, enshrined in the Civil Code, is compatible with

Er besagt, dass jede stetige Funktion einen kleinsten Fixpunkt hat und zeigt sogar, wie man diesen erh¨ alt..

Allerdings terminiert g c nicht, weil es sein Argument so weit auswerten muss, bis klar ist, welcher Wertkonstruktor (hier M a k e ) angewandt wurde. Wir ben¨ otigen also nicht

Wir werden hierbei einige Einschr¨ ankungen vornehmen, die allerdings keine wirklichen Einschr¨ ankungen sind, da man alle anderen Haskell-Programme in unsere erlaubte Syntax

Wir m¨ ussten eigentlich noch zeigen, dass alle Funktionen, die wir in der Definition der Semantik benutzt haben, auch stetig sind.. Da dies allerdings sehr aufw¨ andig ist, m¨

Intuitiv geschieht dies, indem man Typvariablen so ersetzt, dass alle Typgleichungen von der Form τ = τ sind, also zum Beispiel α = Int wird zu Int = Int, indem man α durch

I ” nicht l¨ osbar“ liefert, wenn es keine L¨ osung f¨ ur E gibt, I und andernfalls eine allgemeinste L¨ osung f¨ ur E liefert.. Wir starten mit einer Substitution s, die am

Lehrstuhl Theoretische Informatik Carl Philipp Reh. Funktionales Programmieren