-- a ist der Typ des Status
-- b ist der Typ des Ergebnisses der Berechnung
data State a b = State ( a -> (a, b) )
instance Monad (State a) where
return x = State (\s -> (s,x) )
(>>=) :: (State a) -> ( a -> (State b) ) -> (State b)
(State f1) >>= f2
= State ( \st1 -> let (st2, y) = f1 st1
(State trans ) = f2 y
in trans st2 )
readState :: State a a
readState = State (\st -> (st, st) )
writeState :: a -> State a ()
writeState s = State (\_ -> ( s, () ))
type CountState a = State Int a
tick :: CountState ()
tick = do a <- readState
writeState (a+1)
extract :: CountState a -> (Int, a)
extract (CountState st) = st 0
mul :: Int -> Int -> CountState Int
mul x y = do tick
return (x * y)
test = extract . one
> test 5 ==> (2, 1)
test
ein Tupel zurück, daß die Anzahl der
Aufrufe von mul
und das Ergebnis der Berechnung enthält.
div
und one
hat sich nicht verändert.
>>=
bestimmt, wie Berechnungen verknüpft werden.
data Exception a = Success a | Error String
instance Monad Exception where
return x = Success x
fail s = Error s
(Success x) >>= f = f x
(Error s ) >>= f = (Error s)
catch_ :: Exception a -> (Exception a -> Exception a) -> Exception a
catch_ (Success a) _ = (Success a)
catch_ (Error s) f = f (Error s)
handler :: Num a => Exception a -> Exception a
handler (Error s) = Success 999
div_ :: Int -> Int -> Exception Int
div_ _ 0 = fail "div 0"
div_ x y = return (x ´div´ y)
> one 5 ==> (Success 1)
> one 0 ==> (Error "div 0")
> catch_ (one 0) handler ==> 999
catch_
abgefangen, und von handler
bearbeitet.mul
und one
haben sich nicht verändert.
data Nd a = Nd [a]
instance Monad Nd where
return x = Nd [x]
fail s = Nd []
(Nd [] ) >>= f = Nd []
(Nd (x:xs)) >>= f = let (Nd ys) = f x
(Nd zs) = (Nd xs) >>= f in
(Nd (ys ++ zs) )
fromTo :: Int -> Int -> Nd Int
fromTo a b = Nd [a..b]
many :: Int -> Nd Int
many x = do y <- fromTo 0 x
one y
> many 2 ==> [1, 1]
> many 0 ==> []
fromTo
liefert eine Liste von möglichen Ergebnissen.one
verarbeitet.
IO
ähnelt dem Status-Monad. IO
-Monad.
-- data IO a = IO(Welt -> (Welt, a))
mul :: Int -> Int -> IO Int
mul x y = do putStrLn( "mul " ++ (show x) ++ " " ++ (show y) )
return (x * y)
IO
-Monad
zu extrahieren.
unsafePerfomIO
funktioniert für das IO
-Monad wie die extract
-Funktion.
unsafePerfomIO
ist gefählich, und sollte nur mit Vorsicht benutzt werden.
unsafePerformIO
praktisch sein kann.
trace :: String -> a -> a
trace s x = unsafePerformIO ( putStrLn s >> return x )
noOfOpenFiles :: IORef Int
noOfOpenFiles = unsafePerformIO (newIORef 0)
cast :: a -> b
cast x = let bot = bot
r = unsafePerformIO (newIORef bot)
in unsafePerformIO ( do writeIORef r x
readIORef r )