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