Teil III Funktionale Programmierung in Haskell

Werbung
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
Teil III
Funktionale Programmierung in Haskell
178
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
1. Einführung: Funktionale Programmierung
• hier: informelle Einführung
• ignoriert: monadische Ein-/Ausgabe, Typklassen, . . .
• zum Ausprobieren von Beispielprogrammen: hugs
Funktionales Programm:
• Folge von Typ- und Funktionsdefinitionen
• (oft) interaktive Entwicklungsumgebung erlaubt
Auswertung von Ausdrücken,
in denen die definierten Typen und Funktionen verwendet werden
179
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
2. Funktionsdefinition
Beispiel:
sqr :: Int -> Int
-- optional
sqr x = x * x
max x y = if x > y then x else y
Eigenschaften:
• Funktionen in funktionalen Sprachen sind
(deterministische) Funktionen im mathematischen Sinne
• sie verursachen keine Seiteneffekte ⇒
• Programm leichter nachvollziehbar, wartbar, . . .
• Programmeigenschaften besser beweisbar
180
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
Semantik
• Funktionsdefinitionen werden als Reduktionsregeln genutzt
• Anwendung einer Regel f x1 ...xn = r auf einen
auszuwertenden Ausdruck e:
• in e wird ein Teilausdruck e0 der Form f e1 ...en gesucht
• e0 wird durch r’ ersetzt, wobei
• r’ dadurch entsteht, dass in (einer Kopie von) r
xi durch ei ersetzt wird (für i = 1, . . . , n)
• Grundoperationen (wie +,-,*,...) werden “wie üblich”
ausgewertet
Beispiel:
sqr (sqr 2) ;
;
sqr (2 * 2) ;(2 * 2) * (2 * 2)
4 * (2 * 2) ; 4 * 4 ; 16
181
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
Beispiel: Seiteneffekte in Java
class Foo{
static int x = 0;
public static int m(int y){
return x += y;}
public static void main(String args[]){
System.out.println("Ergebnis: "+m(1)+", "+m(1));}
}
liefert: Ergebnis: 1, 2
⇒ m ist keine Funktion im mathematischen Sinne
182
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
3. Typdefinitionen
3.1 Typabkürzung
• Beispiel: type Gehalt = Int
• stellt bestehenden Typ unter neuem Namen zur Verfügung
• zur Verbesserung der Lesbarkeit
• beide Typen sind kompatibel bzgl. Zuweisung, Vergleich, . . .
183
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
3.2 Algebraische Datentypen
• Beispiel: data
List
| {z }
a
|{z}
Typkon−
Typ−
struktor
variable
= Nil | Cons a (List a)
|
{z
}
Datenkon−
struktoren
einstellig
• ermöglichen neue Typen
• diese sind inkompatibel zu bisherigen
184
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
Datenkonstruktor
• ist uninterpretiertes Funktionssymbol, z.B.
Nil :: List a
Cons :: a -> List a -> List a
• durch Anwendung auf Parameter entsteht ein Wert (Term)
• z.B.: Nil, Cons 1 Nil, Cons 1 (Cons 2 Nil)
• Konstruktorterme sind die in deklarativen Sprachen üblichen
Datenstrukturen
• beachte: durch Typvariablen: parametrischer Polymorphismus
• in Haskell außerdem: Typklassen (vgl. Interfaces)
185
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
Typkonstruktor
• durch Anwendung auf Argumenttypen entsteht neuer Typ
• z.B.
• List Bool
• List (List Int)
Liste boolescher Werte
Liste von Listen ganzer Zahlen
186
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
Verwendung algebraischer Datentypen
durch algebraische Datentypen lassen sich darstellen:
1) Aufzählungstypen, z.B.:
data Bool = True | False
data Farbe = Rot | Gruen | Blau
2) Verbundtypen, z.B.:
data Pair a b = MkPair a b
data Point = MkPoint Float Float
3) Vereinigungstypen, z.B.:
List a (s.o.)
187
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
4) Rekursive Datentypen
• Beispiele:
• List a (s.o.)
• data Tree a = Leaf a |
Branch a (Tree a) (Tree a)
infixr : 5
data [a] = [] | a : [a]
• rekursive Typen können direkt (ohne Zeiger) aufgebaut werden
• Vorteil: (wie in Java, aber im Vergleich zu (z.B.) C, Pascal)
• automatische Speicherverwaltung möglich
→ kein new und dispose nötig
→ einfachere Programmierung
• weniger Fehler:
kein Vergessen von nil, keine Zeiger auf freigegebenen Speicher
188
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
4. Pattern-Matching
• Funktionen (insbesondere mit algebraischen Argumenttypen) werden oft
durch eine Folge von Regeln definiert
• in jeder Regel wird ein Parametermuster vorgegeben
• die (textuell) erste Regel mit einem “passenden” Parametermuster
wird “angewendet”
Beispiel:
statt:
besser:
length l =
length [] = 0
if isEmpty l then 0
length (x:l) = 1 + length l
else 1 + length (tail l)
189
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
5. Typinferenz
• in Funktionsdefinitionen: Typangaben optional
• ohne Typangaben: der allgemeinste Typ wird inferiert, z.B.
length :: [a] -> Int
190
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
6. Funktionen höherer Ordnung
• Funktionen können Funktionen als Argumente und/oder als Ergebnis
haben
→ benutzerdefinierte, problemorientierte Kontrollstrukturen, z.B.
map :: (a -> b) -> [a] -> [b]
map f [] = []
map f (x:l) = f x : map f l
Anwendungsbeispiel: map (+ 1) [1,2,3]
liefert: [2,3,4]
→ Funktion als Datenstruktur (Funktion =
ˆ Tabelle)
191
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
Beispiel: Divide & Conquer
dc :: (a -> Bool) -> (a -> b) -> (a -> [a]) -> ([b] -> b) -> a -> b
dc isSimple solve partition combine problem =
if
isSimple problem
then
solve problem
else combine (map (dc isSimple solve partition combine)
(partition problem))
192
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
Anwendung: Quicksort
qsort l = dc test id split flatten l
test [] = True
test [x] = True
test l = False
split (x:l) = [filter (< x) l, [x], filter (> x) l]
flatten [l1,[x],l2] = append l1 (x:l2)
append [] l = l
append (x:l1) l2 = x : append l1 l2
...
Aufruf, z.B.: qsort [5,7,2,3]
193
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
Beispiel: Pixel-orientiertes Zeichnen
type Point = (Int,Int)
type Picture = Point -> Bool
-- zur Vereinfachung: Typkonvertierungen weggelassen!
add :: Point -> Picture -> Picture
add (x1,y1) p (x,y) = p (x,y) || (x == x1 && y == y1)
zoom :: Int -> Picture -> Picture
zoom v p (x,y) = p (x/v, y/v)
rotate :: Int
-> Picture -> Picture
rotate alpha p (x,y) =
p (cos beta * x - sin beta * y,
sin beta * x + cos beta * y)
where beta = 3.14 - alpha
move :: (Int,Int) -> Picture -> Picture
move (dx,dy) p (x,y) = p (x-dx,y-dy)
overlap :: Picture -> Picture -> Picture
overlap p1 p2 pt = p1 pt || p2 pt
isBlack :: Point -> Picture -> Bool
isBlack pt p = p pt
194
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
Currying
• selten Tupel als Funktionsargument
• stattdessen Currying, d.h.
Funktion wird sukzessiv auf ihre Argumente angewendet
(→ partielle Applikation)
Beispiel:
statt: + :: (Int,Int) -> Int
Currying: + :: Int -> Int -> Int
ermöglicht: (+ 1) :: Int -> Int
z.B. in: map (+ 1) [1,2,3]
195
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
7. Verzögerte Auswertung (lazy evaluation)
• in vielen funktionalen Sprachen:
• statt call-by-value: Argumente werden unausgewertet übergeben
• Auswertung erst “bei Bedarf”
→ unendliche Datenstrukturen
→ Entkopplung von Schleifenrumpf und Schleifensteuerung
• flexibler
• bessere Modularisierung
196
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
Beispiel: Newton-Verfahren in Java
static double eps = 0.001;
public double sqrt(double r, double a0){
double a, a1 = a0;
do a = a1; a1 = (a+r/a)/2.0;
while Math.abs(a - a1) >= eps;
return a1;}
• Beobachtung: Schleifensteuerung und Schleifenrumpf schwer
voneinander zu trennen
197
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
Newton-Verfahren in Haskell
approxs :: Float -> Float -> [Float]
approxs r x = x : approxs r ((x + r/x)/2)
within :: Float -> [Float] -> Float
within eps (x1:(x2:l)) =
if abs (x1-x2) < eps then x2
else
within eps (x2:l)
sqrt :: Float -> Float -> Float -> Float
sqrt x0 eps r = within eps (approxs r x0)
• "Schleifenrumpf" und "Schleifensteuerung" separat
198
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
Variante mit anderer Abbruchbedingung
relative :: Float -> [Float] -> Float
relative eps (x1:(x2:l)) =
if abs (1 -x1/x2) < eps then x2
else relative eps (x2:l)
relsqrt :: Float -> Float -> Float -> Float
relsqrt x0 eps r = relative eps (approxs r x0)
199
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
8. Akkumulation im Parameter
• “Zustandsraum” steckt bei funktionalen Sprachen in den
Parametern
• Zwischenergebnisse als weitere Argumente übergeben
Beispiel:
revers l = rev l []
where rev [] l = l
rev (x:l1) l2 = rev l1 (x:l2)
200
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
9. Weitere Haskell-Features
Wildcards
• erlauben, nicht benötigte Variablen durch "_" zu ersetzen
length (_:xs) = 1 + length xs
length [] = 0
head (x:_)
= x
tail (_:xs) = xs
and False _ = False
and True x
= x
const x _ = x
map (const 1) [1,2,3]
; [1,1,1]
201
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
Lambda-Ausdrücke
• ermöglichen unbenannte Funktionen zu verwenden, z.B.
(.) :: (a -> b) -> (c -> a) -> (c-> b)
f . g = \ x -> f(g(x))
• häufig verwendet in Funktionen höherer Ordnung zu ersetzen, z.B.
map (\x->x*x)
[1,2,3]
; [1,4,9]
202
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
Guards
• ermöglichen Fallunterscheidungen bei einer Funktionsdefinition
max x y | x > y
= x
| x <= y = y
(alternativ: otherwise = y)
203
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
Case-Ausdrücke
• ermöglichen Fallunterscheidung innerhalb eines Ausdrucks
take m xs = case (m,xs) of
(0,_)
-> []
(_,[])
-> []
(n,y:ys) -> y : take (n-1) ys
204
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
Lazy Patterns
• verzögern die Auswertung eines Arguments, das mit einem
Konstruktorterm gematcht wird
• die Auswertung erfolgt, wenn eine der Variablen in dem Term
benötigt wird
reqs = client 0 resps
resps = server reqs
client init ˜(resp:resps) = init : client resp resps
server (req:reqs) = process req : server reqs
process req = req + 1
take 5 reqs
; [0,1,2,3,4]
205
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
Lokale Hilfsdefinitionen
• Definitionen in let-Klauseln dürfen wechselseitig rekursiv sein
• sie sind nur in dem hinter in folgenden Ausdruck verfügbar
let reqs = client 0 resps
resps = server reqs
in take 5 reqs
• Definitionen in einer where-Klausel gelten in allen Teilen einer
bedingten Regel
filter p (x:xs) | p x = x : rest
| otherwise = rest
where rest = filter p xs
206
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
Zermelo-Fränkel-Notation für Listen (List Comprehensions)
• kompakte Notation für Listen
[1..5] =
ˆ [1,2,3,4,5]
[1,3..] =
ˆ [1,3,5,7,...]
[ x*y | x <- [1..3], y <- [1..3], x < y]
allgemein: [ Ausdruck | Generatoren, Guards]
; [2,3,6]
qs [] = []
qs (x:xs) = qs [ y | y <- xs, y < x] ++ [x] ++
qs [ y | y <- xs, y > x]
207
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
Häufig verwendete Funktionen höherer Ordnung
• map bearbeitet jedes Element einer Liste (s.o)
• fold verknüpft die Elemente einer Liste sukzessiv mit einer
binären Operation (z.B. +,*,max,min,++)
foldl :: (a -> b -> a) -> a -> [b] -> a
foldl f z [] = z
foldl f z (x:xs) = foldl f (f z x) xs
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr f z [] = z
foldr f z (x:xs) = f x (foldr f z xs)
foldl (+) 0 [1,2,3,4]
; 10
foldr (+) 0 [1,2,3,4]
; 10
208
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
Häufig verwendete Funktionen höherer Ordnung (2)
• filter wählt Elemente aus einer Liste aus
filter :: (a -> Bool) -> [a] -> [a]
filter p [] = []
filter p (x:xs) | p x = x : filter p xs
| otherwise = filter p xs
filter (<5) [1,9,7,3,8,2]
; [1,3,2]
209
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
Häufig verwendete Funktionen höherer Ordnung (3)
• zipWith verknüpft die Elemente an entsprechenden Positionen
zweier Listen
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith f (x:xs) (y:ys) = f x y : zipWith f xs ys
zipWith _ _ _ = []
zipWith (+) [1,2,3] [4..7]
; [5,7,9]
210
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
Arrays
• der Aufwand beim Zugriff auf ein Element ist nicht konstant sondern
proportional zur Anzahl der Änderungen im Array
• dies ist nur effizient, wenn stets alle Elemente zugleich erzeugt werden
• ansonsten sind Arrays meist nicht günstiger als Listen und werden daher
seltener verwendet
• Arrays werden nicht im Modul Prelude sondern in Array definiert
211
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
Array-Funktionen
Erzeugung: array :: (Ix a) => (a,a) -> [(a,b)] -> Array a b
squares =
array (1,100) [(i, i*i) | i <- [1..100]]
Elementzugriff über Index: (!)
squares ! 4
:: (Ix a) -> Array a b -> a -> b
; 16
Update: (//) :: (Ix a) => Array a b -> [(a,b)] -> Array a b
(squares // [(1,0),(4,20)]) ! 4 ; 20
Ermittlung der Indexgrenzen: bounds :: (Ix a) -> Array a b -> (a,a)
bounds squares ; (1,100)
212
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
Module
• kapseln zusammengehörige Funktionalität
• strukturieren ein Programm und seinen Namensraum
• die exportierten Bezeichner werden in einer Parameterliste
angegeben
• werden keine Parameter angegeben, werden alle Bezeichner
exportiert (auch importierte)
213
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
Beispiel: Modul Dictionary
module Dictionary (Dict, empty, insert, Dictionary.lookup) where
type Dict a b = a -> Maybe b
-- Maybe a = Nothing | Just a
empty :: Dict a b
empty x = Nothing
insert :: (Eq a) => a -> b -> Dict a b -> Dict a b
insert x y d = \z -> if x == z then Just y
else d z
lookup :: a -> Dict a b -> b
lookup x d = d x
214
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
Import von Modulen
module Main
where
import Dictionary (Dict, empty, insert, lookup)
empty = ""
main = Dictionary.lookup "Hund"
(insert ("Hund"++ Main.empty)
"dog"
Dictionary.empty)
215
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
Typklassen
• vermeiden ad-hoc Polymorphismus (z.B. bei +,==,>)
• eine Typklasse bietet eine Schnittstelle, die von Datentypen
implementiert werden kann
• die Schnittstelle besteht aus einer Menge von Funktionen und
ihren Typen
• erfordert eine Funktion Parameter mit einer gewissen
Schnittstelle, so wird dies im Typ der Funktion angegeben
216
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
Beispiel: Typklasse Eq
class Eq a where
(==) :: a -> a -> Bool
data EuroNote = Five | Ten | Twenty | Fifty |
Hundred | TwoHundred |FiveHundred
data Money = Money [EuroNote]
value = foldr (+) 0 . map notevalue
notevalue Five = 5
notevalue Ten
= 10
...
instance Eq Money where
Money m1 == Money m2 = value m1 Prelude.== value m2
217
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
Erweiterung von Typklassen
• die Operationen der "Oberklasse" werden übernommen und um
weitere ergänzt
class
(Eq a) => Ord a
where
(<), (<=), (>=), (>)
:: a -> a -> Bool
max, min
:: a -> a -> a
• mehrere Oberklassen sind möglich
class (Eq a, Show a) => C a where ...
218
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
Abgeleitete Instanzen
• für neue algebraische Typen können Instanzen von Typklassen
von Elementtypen abgeleitet werden
statt
instance
(Eq a) => Eq (Tree a)
(Leaf x)
where
== (Leaf y)
=
x == y
(Branch l1 r1) == (Branch l2 r2)
=
l1 == l2 && r1 == r2
_
=
False
== _
genügt
data
Tree a
=
Leaf a | Branch (Tree a) (Tree a) deriving Eq
219
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
Monaden
• erlauben, neben der eigentlichen Rechnung im Hintergrund
weitere Berechnungen durchzuführen (z.B. Ein- und Ausgaben)
• statt f(g(x)) nun Verknüpfung der Teilberechnungen durch >>=
(bind)
infixl 1
class
>>, >>=
Monad m
where
(>>=)
:: m a -> (a -> m b) -> m b
(>>)
:: m a -> m b -> m b
return
:: a -> m a
fail
:: String -> m a
m >> k
=
m >>= \_ -> k
220
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
Beispiel: Ausdruckauswertung ohne Nebenrechnungen
data Expr = Const Float | Add Expr Expr | Div Expr Expr
eval :: Expr -> Float
eval (Const i) = i
eval (Add e1 e2) = eval e1 + eval e2
eval (Div e1 e2) = eval e1 / eval e2
eval (Div (Add (Const 1) (Const 2)) (Const 3))
; 1.0
221
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
Eine Zustandsmonade
• führt während der Berechnung einen Zustand mit
data SM a = SM (State -> (a,State))
type State = Int
instance Monad SM where
SM c1 >>= fc2 =
SM (\s0 -> let (r,s1) = c1 s0
SM c2 = fc2 r
in
return k
=
c2 s1)
SM (\s -> (k,s))
readSM
:: SM State
readSM
=
updateSM
:: (State -> State) -> SM ()
updateSM f
=
runSM
:: State -> SM a -> (a,State)
runSM s0 (SM c) =
SM (\s -> (s,s))
SM (\s -> ((), f s))
c s0
222
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
Ausdruckauswertung mit Instruktionszählung
eval2 :: Expr -> SM Float
eval2 (Const i)
= updateSM (+1) >> return i
eval2 (Add e1 e2) = updateSM (+1) >> eval2 e1
>>= \v1 -> eval2 e2
>>= \v2 ->return (v1+v2)
eval2 (Div e1 e2) = updateSM (+1) >> eval2 e1
>>= \v1 -> eval2 e2
>>= \v2 ->return (v1/v2)
runSM 0 (eval2 (Div (Add (Const 1) (Const 2)) (Const 3)))
; (1.0,5)
223
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
Die Maybe-Monade
• erlaubt ggf. scheiternde Berechnungen zu verknüpfen
data Maybe a = Nothing | Just a deriving (Eq, Ord, Read, Show)
instance
Monad Maybe
where
(Just x) >>= k
=
k x
Nothing
=
Nothing
return
=
Just
fail s
=
Nothing
>>= k
224
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
Ausdruckauswertung mit Maybe-Monade
eval3 :: Expr -> Maybe Float
eval3 (Const i) = return i
eval3 (Add e1 e2) = eval3 e1 >>= \v1 -> eval3 e2
>>= \v2 ->return (v1+v2)
eval3 (Div e1 e2) = eval3 e1 >>= \v1 -> eval3 e2
>>= \v2 ->
if v2 == 0 then fail "Division durch 0"
else return (v1/v2)
eval3 (Div (Add (Const 1) (Const 2)) (Const 3)) ;
Just 1.0
eval3 (Add (Div (Const 1) (Const 0)) (Const 2)) ;
Nothing
225
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
Die do-Notation
• zur übersichtlicheren Handhabung von Monaden, im Beispiel:
eval4 :: Expr -> Maybe Float
eval4 (Const i)
= return i
eval4 (Add e1 e2) = do v1 <- eval4 e1
v2 <- eval4 e2
return (v1+v2)
eval4 (Div e1 e2) = do v1 <- eval4 e1
v2 <- eval4 e2
if v2 == 0 then fail "Division durch 0"
else return (v1/v2)
eval4 (Div (Add (Const 1) (Const 2)) (Const 3))
;
Just 1.0
eval4 (Add (Div (Const 1) (Const 0)) (Const 2))
;
Nothing
226
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
Die IO-Monade
• sequentialisiert Ein- / Ausgabe-Aktionen
• Ein- und Ausgaben erfolgen ohne Seiteneffekte
data IO a
putChar :: Char -> IO ()
putStr :: String -> IO ()
putStrLn :: String -> IO ()
print :: Show a => a -> IO ()
getChar :: IO Char
getLine :: IO String
getContents :: IO String
interact :: (String -> String) -> IO ()
• es gibt weitere Funktionen zur Dateiverarbeitung
227
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
Beispiel: Verwendung der IO-Monade
sqr :: IO ()
sqr = do
putStrLn "Bitte eine Zahl eingeben:"
str <- getLine
putStr "Das Quadrat Ihrer Zahl ist: "
print (let n = read str in n*n)
main :: IO ()
main = do sqr
main
228
Einführung
Fkt-Def
Typen
Pattern-Matching
Typinferenz
HOF
Lazy Evaluation
Akkumulation
Weitere Features
Frameworks für Haskell
• ∃ Frameworks für GUI-Erstellung (z.B. WxHaskell, Fudgets)
• ∃ Frameworks für Webapplikationen (z.B. Snap, Happstack)
• ∃ Frameworks zur Verwendung von Datenbanken (z.B. HDBC,
HaskellDB, Takusen)
229
Herunterladen