Funktionale Programmierung Das Funktionale Quiz Das Funktionale

Werbung
Das Funktionale Quiz
Funktionale Programmierung
Was weiß man über eine Funktion mit Signatur a -> Int
10.5.2005
Die Funktion ist nicht-strikt
5-6
Das Funktionale Quiz
Das Funktionale Quiz
Ist es möglich, eine Funktion mit dem Typ Int -> a zu schreiben
Nein, denn a müssen Parameter sein, der nicht verwendet wird,
Ergebnisausdruck hat irgendeinen Typ
Ist ++ ein Konstruktor für Listen?
Nein, Aufbau z.B. von [1,2,3] nicht eindeutig:
[1,2,3] = [1] ++ [2,3] = [1,2] ++ [3]
Ja:
returnA :: Int -> a
returnA x = error "ein a"
7-8
Abstraktion über das Muster
Themen heute
Muster:
• Für [] liefere []
• Sonst, wende beliebige Funktion auf erstes Element an und hänge
das Ergebnis vor rekursiven Aufruf
• Higher-Order Funktionen über Listen
• Überladung
• Abstraktion darüber:
map
map :: (a -> b) -> [a] -> [b]
map f []
= []
map f (x:xs) = f x : map f xs
• Algebraische Datentypen
Beob: Funktionen müssen Werte sein
11
Filtern als Muster
Higher-Order Funktionen über Listen
Filtere die Elemente heraus, die Prädikat nicht erfüllen
filter :: (a ->
filter p []
filter p (x:xs)
| p x
| otherwise
• Ziel: Über Berechnugsmuster abstrahieren
Bool) -> [a] -> [a]
= []
• Erstes Muster: Listen homomorph abbilden
Beispiel:
= x : filter p xs
=
filter p xs
doubleAll :: [Int] -> [Int]
doubleAll []
= []
doubleAll (x:xs) = 2*x : doubleAll xs
signAll :: [Int] -> [Bool]
signAll []
= []
signAll (x:xs) = (x >= 0) : signAll xs
12
Vorteile von foldr
Abstrahieren über primitive Rekursion
• Wiederverwendung des Musters
Schablone für p.R. war:
f []
= ...
f (x:xs) = ... x ... (f xs) ... x ...
• Primitive Rekursion wird offensichtlich
Abstraktion darüber braucht:
• In Beweisen können Eigenschaften von foldr verwendet werden
• Ausdruck für []
• Ausdruck, der aus x und f xs den Wert für f (x:xs) berechnet
15
Funktionen als Ergebnisse
Abstrahieren über primitive Rekursion
• Schon mehrfach vorgekommen: curry, (.),twice
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr cons nil []
= nil
foldr cons nil (x:xs) = cons x (foldr cons nil xs)
• Außerdem eigentlich ständig, da Funktionen nur einstellig: f 1 2
ist ja eigentlich (f 1) 2
• Explizt: Über lokale Funktionsdefinition:
addSubstNum :: Int -> ((Int -> Int), (Int -> Int))
addSubstNum n = (addN, substN)
where
addN m
= n+m
substN o = n-o
16
• nil ist der Wert für []
• cons berechnet aus erstem Element und Funktionswert für xs den
Funktionswert für x:xs
sumList :: [Int] -> Int
sumList = foldr (+) 0
Beweise für Higher-Order-Funktionen
Lambda-Notation: Funktion als Ausdruck
• Ist ein Parameter eine Funktion, dann durchreichen
• Der Ausdruck \x -> e wertet zu einer Funktion aus, die x als
Parameter und e als Rumpf hat
• Prinzip der Erweiterbarkeit: Zwei Funktionen sind gleich, wenn sie
für alle Argumente die gleichen Resultate ergeben.
Z.Z.: f . id = f
• Damit addSubstN:
addSubstNum n = ((\m -> n+m), (\o -> n-o))
(f . id) x = f (id x) = f x
• Auch mit mehreren Parametern: add = \x y -> x + y
19
Beispielbeweis
Allgemeine Syntax für Lambda-Notation
Z.Z. map f . rev = rev . map f
Induktion über Liste
Induktionsanfang: Trivial
Def. rev
ÜA
Linke Seite: map f (rev x:xs)
=
map f (rev xs++[x]) = map f
Def. map
IA
(rev xs) ++ map f [x]
=
map f (rev xs) ++ [f x] = rev (map f xs)
++ [f x]
Rechte Seite: rev (map f (x:xs))
rev (map f xs ++ [f x]
Def map
Dev rev
=
rev (f x : map f xs)
=
20
\ pat1 ... patN -> e
"Anonyme Funktion"
Lambda-Notation ist Teil des Haskell-Kerns, f x ... = e wird
übersetzt nach f = \x ... -> e
Typklassen
Weitere Theoreme
• class Eq a where
(==) :: a -> a -> Bool
map (f . g) xs
= (map f . map g) xs
(filter p . map f) xs = (map f . filter (p . f)) xs
map f (reverse xs)
= reverse (map f xs)
map f (ys++xs)
= map f ys ++ map f xs
• Damit: elem :: Eq a => a -> [a] -> Bool
• Eq a ist der Kontext
23
Typklassen definieren
Überladung
• class C ty where idecls
• Beob: Manche Funktionen funktionieren nur auf bestimmten Typen
• Abgeleitete Klassen: class scontext => C ty where idecls
• Bsp: Element-Check für Listen braucht Gleichheit auf
Listenelementen
• C: Name der Klasse
• ty: Typvariable (nur eine!)
1. Möglichkeit: Gleichheit mit übergeben:
elem :: a -> [a] -> (a -> a -> Bool) -> Bool
• idecls sind Typsignaturen der Operationen oder Defaultdefinitionen
2. Möglichkeit: Typ der Elemente einschränken
elem :: a -> [a] -> Bool, a hat Gleichheit
• Superklassen:
scontext
->
simpleclass
| ( simpleclass1 , ... , simpleclassn )
simpleclass
->
C ty
• a muss zu einer bestimmten Klasse Typen gehören: Typklasse
24
Instanzdeklarationen
Beispiel
• Fügen einen Typ einer Typklasse hinzu
• Geben die Definitionen der überladenen Funktionen an
• Syntax:
instance Class Type [where decls]
class Eq a => Ord a where
(<),(<=),(>),(>=) :: a -> a -> Bool
• Beispiel:
instance Eq Bool where
True == True = True
False == False = True
_
== _
= False
27
Instanzdeklaration mit Kontext
Defaultdefinitionen
• Bei der Instanzdeklaration Typklassen voraussetzen
• Geben Implementierung an, können "überschrieben" werden
• Syntax:
instance [scontext =>] Class Type [where idecls]
• Beispiel:
instance
[]
==
x:xs ==
_
==
• Häufig wechselseitig rekursiv
class
Eq a
[]
y:ys
_
=> Eq [a] where
= True
= x == y && xs == ys
= False
28
Eq a where
(==), (/=) :: a -> a -> Bool
x /= y = not (x == y)
x == y = not (x /= y)
Produkt-Typen
Eingebaute Typklassen
• Typen mit Gleichheit: Eq s.o.
• Konstruktoren haben Argumente
• Typen mit totaler Ordnung:
class (Eq a) => Ord a where
compare
:: a -> a -> Ordering
(<), (<=), (>=), (>) :: a -> a -> Bool
max, min
:: a -> a -> a
• data People = Person String Int
| DeadPerson String Int Int
• Dann ist Person :: String -> Int -> People
• Typen die angezeigt werden können
class Show a where
show
:: a -> String
• Funktion darauf:
instance Show People where
show (Person name born) =
name ++ " * " ++ show born
show (DeadPerson name born died) =
name ++ " * " ++ show born ++
" + " ++ show died
31
Allgemeine Syntax
• Aufzählungstypen
class Enum a where
succ, pred
:: a -> a
toEnum
:: Int -> a
fromEnum
:: a -> Int
enumFrom
:: a -> [a]
enumFromThen
:: a -> a -> [a]
enumFromTo
:: a -> a -> [a]
enumFromThenTo
::
a ->Datentypen
a -> a -> [a]
Algebraische
• Selbstdefinierte Typen
• Bezug zur Algebra: Ein Typ, Definition durch Angabe von
Konstruktoren
data Typename =
• Aufzählungstypen:
Constr1 Typ11 ...
| Constr2 Typ21 ...
...
| ConstrN TypN1 ...
data Season = Spring | Summer | Autumn | Winter
data Bool = True | False
data Ording = LT | EQ | GT ???
• Funktionen darauf: Wie gehabt, d.h. Pattern-Matching mit
Konstruktoren
32
Funktionen über rekursive Datentypen
Typklasseninstanzen ableiten
• Induktiv definiert => Funktionen darüber: rekursiv
•
maxDepth
maxDepth
maxDepth
Beispiel:
max
• Operationen automatisch erzeugen
:: IntTree -> Int
EmptyIntTree
= 0
(Node _ t1 t2) =
(maxDepth t1) (maxDepth t2)
data Temp = Hot | Cold
deriving (Eq, Ord, Enum, Show, Read)
35
Primitive Rekursion für algebraische Datentypen
Rekursive Datentypen
Gemäß der Definition des Typs:
• Für nicht-rekursive Konstuktoren ist der Wert direkt angegeben
• Typ ist gleichzeitig Argument für Konstruktor
• Für rek. Konstruktoren werden die Werte der Funktion an den
rekursiven Teilausdrücken verwendet, um das Ergebnis zu
berechnen
• Definition ist also induktiv
• Beispiel:
data IntTree = EmptyIntTree
| Node Int IntTree IntTree
sumIntTree :: IntTree -> Int
sumIntTree EmptyIntTree
= 0
sumIntTree (Node n t1 t2) =
n + sumIntTree t1 + sumIntTree t2
36
Allgemeine Syntax
topdecl
->
simpletype
constrs
constr
deriving
->
->
->
->
Abstraktion über primtive Rekursion
data [context =>] simpletype =
constrs [deriving]
tycon tyvar1 ... tyvark
constr1 | ... | constrn
Con atype1 ... atypek
deriving (dclass |
(dclass1, ... , dclassn))
Allgemein:
• Ersetze die Konstruktoren durch Funktionsaufrufe
• Für rekrusive Argumente, rufe Abstraktion auf
39
Der Typ Maybe
Polymorphe Datentypen
• Idee: Einige Argumente der Konstruktoren sind Typvariablen
Eingebaut als data Maybe a = Nothing | Just a
• Beispiel:
data List a = Nil
| Cons a (List a)
• Entspricht Berechnung, die eventuell fehlgeschlagen ist
40
Herunterladen