ProInformatik: Funktionale Programmierung Woche 2

Werbung
Informatik Institut, Fachbereich Mathematik und Informatik
ProInformatik: Funktionale Programmierung
Woche 2: 4.-8.8.2008
Dozentin: Maria Knobelsdorf
Tutorin, Tutor: Peggy Sabri, Dirk Wiesenthal
28.7 – 22.8.2008
Raum 005, Takustr. 9
14195 Berlin
Tag 14, ILOs
•
•
•
•
•
•
•
Wissen:
Wiederholung des λ-Kalküls
α-Konversion
Typklassen in Haskell
Anwenden:
Reduzieren von λ-Ausdrücken
Typklassen in Haskell definieren
ProInformatik, Funktionale Programmierung, 28.7-22.8.2008, M. Knobelsdorf
2
λ-Kalkül – eine kurze Wiederholung
• Wozu λ-Kalkül? Ursprüngliches Ziel war eine
Definition für Funktionen zu finden, die eine extrem
einfache Syntax hat.
• Das ganze wurde benötigt, um besser zu definieren
was Berechenbarkeit ist, bzw. was berechenbare
Funktionen sind. (Mehr zu Berechenbarkeit in GTI, Grundlagen
der Theoretischen Informatik, im Sommersemester)
• Das λ-Kalkül wurde jedoch auch die Grundlage für
Funktionale Programmiersprachen
ProInformatik, Funktionale Programmierung, 28.7-22.8.2008, M. Knobelsdorf
3
Die Syntax des λ-Kalküls
Ein λ-Ausdruck A ist syntaktisch in BNF definiert als:
<λ-Ausdruck> :=
<Variable>|<Abstraktion>|<Application>
<Variable> := a|b|…z|f|… --eine abzählbar unendliche
Menge an Variablen
<Abstraktion> := λ<Variable>.<λ-Ausdruck>
<Application> := (<λ-Ausdruck>) <λ-Ausdruck>
ProInformatik, Funktionale Programmierung, 28.7-22.8.2008, M. Knobelsdorf
4
Die Syntax des λ-Kalküls
• Im λ-Kalkül gibt es nur Variablen, Abstraktionen
und Applicationen
• Es gibt keine Zahlen, Wahrheitswerte, keine Typen
• Funktionen haben keinen Namen sondern werden
anonymisiert als Abstraktion oder als Variable
dargestellt
ProInformatik, Funktionale Programmierung, 28.7-22.8.2008, M. Knobelsdorf
5
Konventionen
• Die Abstraktion ist rechtsassoziativ:
λx. λy.λz.(x) y z (λx. (λy.(λz.(x) y z)))
• Warum? Wegen der Definition von <Abstraktion>:
Alles rechts vom Punkt ist ein weiterer
<λ-Ausdruck>
(λx. λy.λz.(x)y) z (λx.<λ-Ausdruck>)z
ProInformatik, Funktionale Programmierung, 28.7-22.8.2008, M. Knobelsdorf
6
Daher kann man Abstraktion und Application auch
definieren als:
<Abstraktion> := (λ<Variable>.<λ-Ausdruck>)
<Application> := ((<λ-Ausdruck>)<λ-Ausdruck>)
• Wodurch die Rechtsassoziativität sichtbar gemacht
wird
• Um Klammern zu sparen werden dann bei der
Application wegen Linksassoziativität die inneren
Klammern weggelassen:
• <Application> (x y z) (((x) y) z)
ProInformatik, Funktionale Programmierung, 28.7-22.8.2008, M. Knobelsdorf
7
β-Reduktion: Auswerten von λ-Ausdrücken
• λ-Ausdrücke werden β-Redex genannt, wenn sie die
Form haben:
(λ<Variable>.<λ-Ausdruck>) <λ-Ausdruck>
• Ein λ-Ausdruck in Redexform kann ausgewertet werden,
indem mit der sog. β-Reduktion eine Termersetzung
ausgeführt wird:
Sei x =<Variable> und E,Q = <λ-Ausdruck>, die
β-Reduktion ist definiert als:
(λx.E)Q ->β E[x/Q] := λ-Ausdruck, der aus E entsteht
durch Ersetzen aller freien
Variablen x in E durch Q
• Ein λ-Ausdruck wird Normalform genannt, wenn er keine
β-Redexe mehr enthält.
ProInformatik, Funktionale Programmierung, 28.7-22.8.2008, M. Knobelsdorf
8
Beispiele
(λx.x) y ->β y
(λx.y) z ->β y
(λx. λy.(x) y) a ->β λy.(a) y
(((λx. λy.λz.(x) (y) z)a)b)c ->β (a)(b)c
((λx. λy.(x) y) y)b ->β (y) b
ProInformatik, Funktionale Programmierung, 28.7-22.8.2008, M. Knobelsdorf
9
α-Konversion
• Die α-Konversion erlaubt gebundene Variablen
umzubennen, um Konflikte zu vermeiden:
Sei x =<Variable> und E,Q = <λ-Ausdruck>, die
α-Konversion ist definiert als:
(λx.E)Q ->α (λy.E‘)Q, wobei alle freien Vorkommen
von x in E durch y ersetzt
werden
ProInformatik, Funktionale Programmierung, 28.7-22.8.2008, M. Knobelsdorf
10
Auswertungsreihenfolge
Wo soll man anfangen?
• Man fängt wie beim Syntaxbaum mit dem
gesamten <λ-Ausdruck> an und sucht den ersten
β-Redex und wertet ihn aus und macht dann
weiter. (Das ist eine Festlegung!)
Da per Definition die <Abstraktion> rechtsassoziativ
und die <Application> linksassoziativ sind, entsteht
dadurch automatisch die Reihenfolge:
Soweit wie möglich links und außen anfangen:
ProInformatik, Funktionale Programmierung, 28.7-22.8.2008, M. Knobelsdorf
11
(((λx. λy.λz.(x) (y) z)a)b)c (<λ-Ausdruck>) c ((<λ-Ausdruck>))b)c (((<λ-Ausdruck>))a)b)c
(((
(((
λx. λy. λz. (x)(y) z
λx. (λy.(λz.(x)(y) z))
)a)b)c )a)b)c
=> Links und außen angefangen und vorgearbeitet
zum ersten β-Redex (λx. < λ-Ausdruck>) a
ProInformatik, Funktionale Programmierung, 28.7-22.8.2008, M. Knobelsdorf
12
Beispiele
(λx.λy.λz.(x)(y)z) a ->β ?
λx.(λy.y)x ->β ?
ProInformatik, Funktionale Programmierung, 28.7-22.8.2008, M. Knobelsdorf
13
Church-Rosser Theorem
• Was wenn man anders vorgeht und dadurch
verschiedene Auswertungsreihenfolgen möglich
sind?
Theorem von Church-Rosser
• Sei E ein β-Redex und M und N verschiedene
Ergebnisse von Auswertungsreihenfolgen der βReduktion mit:
E ->β* M und E ->β* N, dann gibt es ein Z, so
dass M ->β* Z und N ->β* Z
ProInformatik, Funktionale Programmierung, 28.7-22.8.2008, M. Knobelsdorf
14
Left-most, Outer-most
• Die Festlegung: soweit wie möglich links und außen
anfangen ist also korrekt
• Ist das auch gut? Im Sinne von optimal?
• Wie ist das in Haskell?
• β-Reduktion und Lazy Evaluation
Exakte Auswertung eines Haskell-Ausdrucks
-> Master-Veranstaltung:
„Fortgeschrittene Aspekte der Funktionalen Programmierung“,
bei E. Fehr, im Sommer-Semester!
ProInformatik, Funktionale Programmierung, 28.7-22.8.2008, M. Knobelsdorf
15
Typklassen in Haskell
• Welche Signatur hat elemA?
elemA e [] = False
elemA e (x:xs)
|e==x = True
|otherwise = elemA e xs
elemA :: a -> [a] -> Bool
Wobei a Elemente sind, die man auf Gleichheit
überprüfen kann, also alle Datentypen, die den
logischen Vergleich (==) auf ihren Werten zulassen
ProInformatik, Funktionale Programmierung, 28.7-22.8.2008, M. Knobelsdorf
16
Typklasse in Haskell
• In Haskell wird eine Menge von Datentypen, die für
bestimmte Funktionen definiert sind, Typklasse
genannt:
class Eq a where
(==)::a->a->Bool
elemA :: Eq a => a -> [a] -> Bool
ProInformatik, Funktionale Programmierung, 28.7-22.8.2008, M. Knobelsdorf
17
Beispiel
allEqual :: Int -> Int -> Int -> Bool
allEqual x y z = (x==y) && (y==z)
Kann verallgemeinert werden zu:
allEqual :: Eq a=> a -> a -> a -> Bool
ProInformatik, Funktionale Programmierung, 28.7-22.8.2008, M. Knobelsdorf
18
Typklassen: Definition
class <Klassenname> <Variable x> where
…Signaturen von Funktionen, die x verwenden…
Bsp.
class Visible a where
toString :: a -> String
size :: a -> Int
• Zu beachten: in der Typklasse sind nur Signaturen
angegeben, nicht die Definitionen der Funktion
ProInformatik, Funktionale Programmierung, 28.7-22.8.2008, M. Knobelsdorf
19
Instances of a type class
• Um einen Datentyp als Ausprägung einer Typklasse
zu definieren wird eine sog. Instance definiert:
instance <Typklasse T> <Datentyp D> where
Funktionsdefinitionen der in T definierten
Funktionen mit D
• Typklassen und instances verhalten sich wie in
objektorientierten Sprachen Interfaces und
Klassen, die diese implementieren!
ProInformatik, Funktionale Programmierung, 28.7-22.8.2008, M. Knobelsdorf
20
Bsp.
Bsp.
class Visible a where
toString :: a -> String
size :: a -> Int
instance Visible Bool where
toString True = “True“
toString False = “False“
size True = 1
size False = 0
ProInformatik, Funktionale Programmierung, 28.7-22.8.2008, M. Knobelsdorf
21
Überladene Funktionen
instance Visible Int where
toString x = (horner x):““
size x = x
horner z = …
instance Visible Char where
toString c = c:““
size c = 1
Die Methoden einer Typklasse werden ab zwei
Instances überladen, d.h. mehrmals definiert für
verschiedene Datentypen
ProInformatik, Funktionale Programmierung, 28.7-22.8.2008, M. Knobelsdorf
22
Default functions
• Innerhalb der Typklassendefinition können
Funktionen auch definiert werden
• Diese default Funktionen können nachher in den
instances überschrieben werden:
class Eq a where
(==), (/=)::a->a->Bool
x /= y = not (x==y)
x == y = not (x/=y)
• In dem Fall kann man als Analogie zu
objektorientierten Sprachen das Ganze als
abstrakte Klasse vorstellen.
ProInformatik, Funktionale Programmierung, 28.7-22.8.2008, M. Knobelsdorf
23
Beispiele
func::Eq a =>(a,a)->(a,a)
func (a,b) = (a==b,b)
ProInformatik, Funktionale Programmierung, 28.7-22.8.2008, M. Knobelsdorf
24
Zusammengesetzte instances
instance (Eq a) => Eq [a] where
(==) [] [] = True
(==) [] (x:xs) = False
(==) (x:ys) [] = False
(==) (x:xs) (y:ys) = x == y && xs == ys
• Listen vom Typ a können nur dann mit (==)
verglichen werden, wenn das für Werte von a gilt.
• Implementierung gibt an, wie das geschieht.
ProInformatik, Funktionale Programmierung, 28.7-22.8.2008, M. Knobelsdorf
25
Typklassen aus Typklassen definieren
• Typklassen können voneinander erben:
Bsp. Die Typklasse Ord:
class Eq a => Ord a where
(>), (<=), (>), (>=)::a->a->Bool
• Jede instance von Ord muss nicht nur die
Funktionen von Ord, sondern auch von Eq
definieren.
=> Vollständige Definition aller Typklassen und
instances in der Haskell Bibliothek. -> Prelude.hs
ProInformatik, Funktionale Programmierung, 28.7-22.8.2008, M. Knobelsdorf
26
Typklasse Ord
Was ist Ordering, LT, EQ und GT?
Antwort:
Ordering ist ein algebraischer Datentyp mit:
data Ordering = LT | EQ | GT
Mehr dazu morgen!
ProInformatik, Funktionale Programmierung, 28.7-22.8.2008, M. Knobelsdorf
27
Weitere Klassen
Enum ermöglicht Listen mit .. Zu definieren:
[
[
[
[
n .. ] = enumFrom n – Pseudocode
n, m .. ] = enumFromThen n m
n .. m ] = enumFromTo n m
n, n' .. m ] = enumFromThenTo n n' m
ProInformatik, Funktionale Programmierung, 28.7-22.8.2008, M. Knobelsdorf
28
Num erbt von Eq und Show und definiert die Funktionen
(*), (+), (-):
class (Eq a, Show a) => Num a where
(+) :: a -> a -> a
(-) :: a -> a -> a
(*) :: a -> a -> a
instance Num Int where
x+y = primAdd x y – systemdefiniert
...
class Num a => Fractional a where
(/) :: a -> a -> a
ProInformatik, Funktionale Programmierung, 28.7-22.8.2008, M. Knobelsdorf
29
Mehrere Oberklassen
• Ganze Zahlen sind aufzählbar (Enum) und
numerisch (Num). Integral Subklasse von Enum
und Num
class (Enum a, Num a) => Integral a where
quot, rem, div, mod :: a -> a -> a
quotRem, divMod :: a -> a -> (a,a)
even, odd :: a -> Bool
toInteger :: a -> Integer
-- toInt :: a -> Int
ProInformatik, Funktionale Programmierung, 28.7-22.8.2008, M. Knobelsdorf
30
Typherleitung
1. Überprüfen, welche Parameter es gibt
2. Für jeden Parameter analysieren, was in der
Funktion mit ihm geschieht
3. Aus 2. ableiten, welchen Typ jeder Parameter
mindestens haben muss, damit die
4. Funktionsauswertung durchgeführt werden kann
5. Die analysierten Typen aus 3. zusammenfassen zu
einem Obertyp
6. Signatur bestimmen
ProInformatik, Funktionale Programmierung, 28.7-22.8.2008, M. Knobelsdorf
31
Herunterladen