Eine Folie pro Seite

Werbung
Funktionale Programmierung
28.6.2005
1
Das Funktionale Quiz
Was ist der Unterschied zwischen der Animation-Bibliothek und
funktional-reaktiver Programmierung?
"Reaktivität", d.h. Reaktion auf Ereignisse
2-3
Das Funktionale Quiz
Warum werden die Operatoren ->> und =>> so häufig verwendet?
untilB wartet auf Event und liefert neues Behaviour
Neues Behaviours ist Wert des Ereignisses, ->> und =>> geben
Events neue Werte
untilB :: Beh a -> Ev (Beh a) -> Beh a
(->>) :: Ev a-> b-> Ev b
4-5
Themen heute
• Felder mit Labeln
• Monaden kombinieren
• Typinferenz
6
Beispiel: Felder mit Labeln
Aus der Grafik-Bibliothek:
data Event
= Key {char :: Char, isDown :: Bool}
| Button {pt :: Point, isLeft,isDown :: Bool}
| MouseMove {pt :: Point}
...
7
Felder mit Labeln
Argumente der Konstruktoren können Namen haben
Syntax: Constr {name :: type,...}
Semantik: wie vorher und zusätzlich:
• Konstruktoraufruf mit Feldern: Constr {name = Wert,...
Dabei Reihenfolge der Felder egal.
Z.B. k = Key {isDown = False, char = 'a'}
• Feldnamen sind Funktionen, die Felder extrahieren.
Z.B. char k--> 'a'
• Selektives Update, d.h. aus bestehendem Wert neuen erstellen und
dabei einzelne Felder verändern.
Z.B. k {isDown = True}--> Key 'a' True
• Selektiv Variablen binden beim Pattern-Matching
8
Neue Allgemeine Syntax für algebraische Datentypen
topdecl
->
simpletype ->
constrs
->
constr
->
|
deriving
->
data [context =>] simpletype =
constrs [deriving]
tycon tyvar1 ... tyvark
constr1 | ... | constrn
Con atype1 ... atypek
Con { fielddecl1 , ... , fielddecln }
deriving (dclass |
(dclass1, ... , dclassn))
9
Mehrere Monaden
Eine Monade kapselt i.d.R. eine Sorte von Berechnungen
Oftmals sind mehrere Sorten von Berechungen notwendig
Möglichkeiten:
• Monade definieren, die alles benötigte kann
Nachteil: nicht modular
• Monaden kombinieren
10
Monaden kombinieren
Sehr aufwendig, wenn bestehende Monaden nicht verändert werden
sollen
Einfacher: Monaden definieren, die zu bestehender Basis-Monade
weitere Berechnung hinzufügen "Monaden-Transformer"
Idee: Berechnungen der Basis-Monade sind Ergebnisse des
Transformers
Operationen der Basis-Monade werden in die neue Monade geliftet
11
Monaden-Transformer für Maybe-Monade
Berechungen ausführen, bis Fehler auftritt
newtype MaybeT m a = MaybeT (m (Maybe a))
returnMT :: Monad m => a -> MaybeT m a
returnMT v = MaybeT (return (Just v))
return gehört zur Basis-Monade
12
Einschub: $
($) :: (a -> b) -> a -> b
f $ a = f a
Hilft Klammern sparen
13
>>= für MaybeT
>>= der Basis-Monade ausführen, wenn noch kein Fehler
aufgetreten ist
bindMT :: Monad m =>
MaybeT m a -> (a -> MaybeT m b) -> MaybeT m b
(MaybeT x) `bindMT` f =
MaybeT $
do r <- x
case r of
Just v -> let MaybeT x = f v in
do r2 <- x
return r2
Nothing -> return Nothing
14
Instanzdeklaration für MaybeT
instance Monad m => Monad (MaybeT m) where
return = returnMT
(>>=) = bindMT
fail s = MaybeT (return Nothing)
15
Liften der Basis-Operationen
Nichts schlägt fehl:
liftMaybe :: Monad m => m a -> MaybeT m a
liftMaybe m = MaybeT (do v <- m
return (Just v))
16
Beispiel: MaybeT auf IO anwenden
putStrLnMB :: String -> MaybeT IO ()
putStrLnMB s = liftMaybe (putStrLn s)
s ::
s = do putStrLnMB "eins"
fail "Fehler!"
putStrLnMB "ywei"
runIOMB :: MaybeT IO a -> IO a
runIOMB (MaybeT x) = x
runIOMB s gibt nur "eins" aus
17
Transformer für Zustandstransformer
newtype StateTT m s a = StateMonad (s -> m (a,s))
returnSTT :: Monad m => b -> StateTT m c b
returnSTT v = StateMonad (\s -> return (v,s))
bindSTT :: Monad m => StateTT m b c ->
(c -> StateTT m b d) -> StateTT m b d
bindSTT (StateMonad x) f =
StateMonad (\s -> do (v,s') <- x s
let StateMonad g = f v in
g s')
return und >>= sind aus der Basis-Monade
18
Operationen für Zustandstransformer
fetchST :: Monad m => StateTT m s s
fetchST = StateMonad (\ s -> return (s,s))
storeST :: Monad m => v -> StateTT m v ()
storeST s = StateMonad (\ _ -> return ((),s))
return ist wieder aus Basis-Monade
19
Liften und laufen lasen für Zustandstransformer
liftStateT :: Monad m => m a -> StateTT m s a
liftStateT p
=
StateMonad $ \s -> do y <- p
return (y,s)
runStateT :: Monad m => StateTT m s a -> s -> m (a,s)
runStateT (StateMonad f) = f
20
Beispiel: StateTT auf Roboter-Monade anwenden
moveMemoT :: StateTT Robot a ()
moveMemoT = liftStateT move
getPositionT :: StateTT Robot a Position
getPositionT = liftStateT getPosition
...
runMemoRobotT :: s -> MemoRobotT s () -> IO ()
runMemoRobotT init r =
runRobot $ do (v,s) <- runStateT r init
return ()
21
move mit Zugriff auf State
Zustand: Liste der besuchten Positionen
moveMemoTtrail :: StateTT Robot [(Int,Int)] ()
moveMemoTtrail = do oldTrail <- fetchST
pos <- getPositionT
storeST (pos:oldTrail)
moveMemoT
22
Alternatives move
Zustand: Anzahl der Schritte
moveMemoTtick :: StateTT Robot Int ()
moveMemoTtick = do oldTicks <- fetchST
storeST (1 + oldTicks)
moveMemoT
23
Roboter, der an schon bekanntem Ort dreht
been = do trail <- fetchST
pos <- getPositionT
condT blockedT turnRightT moveMemoTtrail
if pos `elem` trail
then turnRightT
else moveMemoTtrail
been
24
Probleme
Manche Monaden interagieren in nicht-trivialer Weise
• MaybeT (StateT s a) liefert im Fehlerfall Store bei Abbruch
• StateTT Maybe a s liefert im Fehlerfall keinen Store
Transformer für Listen-Monade verlangt, dass Argument kommutativ
ist
25
Roboter-Simulator ohne Transformer
Zustandsmonade entspricht impliziten Parameteren
tremaux :: Robot ()
tremaux = penDown >> (runTremaux [])
where runTremaux :: Trail -> Robot()
runTremaux trail =
while (isnt aimReached)
(do pos <- getPosition
newTrail <- moveTremaux trail
pos
runTremaux newTrail)
moveTremaux :: Trail -> Position -> Robot Trail
26
Typinferenz für parametrische Polymorphie
Typinferenz: Typen eines Programms herleiten
Sprache: λ-Kalkül mit let und Rekursion
Also keine Typklassen, algebraischen Datentypen,...
Literatur: Thiemann, 15.4 und 15.5.1
27
Herunterladen