-
Notifications
You must be signed in to change notification settings - Fork 4
/
effektsysteme.hs
160 lines (125 loc) · 4.74 KB
/
effektsysteme.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
{-# LANUGAGE ExistentialQuantification, KindSignatures, GADTs, Rank2Types #-}
module Main where
import Control.Monad.Error hiding (lift)
import Data.IORef
import System.Exit
--------------------------------------------------------------------------------
-- Freie Monaden über freien Funktoren über Termkonstruktoren
data Prog t a =
Pure a | forall r. Step (t r) (r -> Prog t a)
lift :: t a -> Prog t a
lift x = Step x Pure
instance Functor (Prog t) where
fmap f (Pure x) = Pure (f x)
fmap f (Step u k) = Step u (fmap f . k)
instance Monad (Prog t) where
return = Pure
Pure x >>= f = f x
Step u k >>= f = Step u ((>>= f) . k)
--------------------------------------------------------------------------------
-- Beispiel: Die State-Monade spezifiert über die Signatur ihrer möglichen
-- Nebenwirkungen und eine operationelle Semantik
data StateI :: * -> * -> * where
Get :: StateI s s
Put :: s -> StateI s ()
type State s = Prog (StateI s)
get :: State s s
get = lift Get
put :: s -> State s ()
put st = lift (Put st)
runState :: State s a -> s -> (a,s)
runState (Pure x) st = (x,st)
runState (Step Get k) st = runState (k st) st
runState (Step (Put st') k) st = runState (k ()) st'
evalState :: State s a -> s -> a
evalState = ((.) . (.)) fst runState
--------------------------------------------------------------------------------
-- Beispiel: Einfaches Multitasking (über einer Basismonade)
data ProcessI :: (* -> *) -> * -> * where
Lift :: m a -> ProcessI m a
Stop :: ProcessI m a
Fork :: ProcessI m Bool
Yield :: ProcessI m ()
liftBase :: m a -> Prog (ProcessI m) a
liftBase = lift . Lift
-- Interpreter, der nach jeder Aktion in der Basismonade die Kontrolle
-- an den nächsten Prozess weitergibt
runProcessForced :: (Monad m) => Prog (ProcessI m) a -> m ()
runProcessForced = schedule . (:[])
where
schedule [] = return ()
schedule (m:ms)
| Pure x <- m = schedule ms
| Step (Lift u) k <- m = u >>= \x -> schedule (ms ++ [k x])
| Step Stop k <- m = schedule ms
| Step Fork k <- m = schedule $ ms ++ [k True, k False]
| Step Yield k <- m = schedule $ ms ++ [k ()]
-- Interpreter, der nur bei Verwendung von Yield die Kontrolle an den
-- nächsten Prozess übergibt
runProcessCooperative :: (Monad m) => Prog (ProcessI m) a -> m ()
runProcessCooperative = schedule . (:[])
where
schedule [] = return ()
schedule (m:ms)
| Pure x <- m = schedule ms
| Step (Lift u) k <- m = u >>= \x -> schedule (k x : ms)
| Step Stop k <- m = schedule ms
| Step Fork k <- m = schedule $ [k False] ++ ms ++ [k True]
| Step Yield k <- m = schedule $ ms ++ [k ()]
exProcess :: Prog (ProcessI IO) ()
exProcess = do
liftBase $ putStrLn "Beginn."
inChild <- lift Fork
let debug msg = liftBase $ putStrLn $ (if inChild then "[K]" else "[E]") ++ " " ++ msg
if inChild
then do
debug "Im Kindprozess."
forM_ [1..5] $ \n -> do
when (even n) $ lift Yield
debug $ show n
debug "Fertig im Kind."
lift Stop
else do
debug "Im Elternprozess."
forM_ [10..15] $ \n -> do
when (even n) $ lift Yield
debug $ show n
debug "Fertig im Elternprozess."
debug "Ganz fertig (nur der Elternprozess sollte hierhin gelangen)."
--------------------------------------------------------------------------------
-- Koprodukt von Monaden
data Sum m n a = Inl (m a) | Inr (n a)
type Coprod m n = Prog (Sum m n)
inl :: m a -> Coprod m n a
inl x = Step (Inl x) Pure
inr :: n a -> Coprod m n a
inr x = Step (Inr x) Pure
elim
:: (Monad m, Monad n, Monad s)
=> (forall a. m a -> s a)
-> (forall a. n a -> s a)
-> (forall a. Coprod m n a -> s a)
elim phi psi (Pure x) = return x
elim phi psi (Step (Inl m) k) = phi m >>= elim phi psi . k
elim phi psi (Step (Inr n) k) = psi n >>= elim phi psi . k
--------------------------------------------------------------------------------
-- Beispiel: Koprodukt aus State- und Error-Monade
type Err e = Either e
type M = Coprod (State Int) (Err String)
exM :: M Int
exM = do
st <- inl get
if st <= 0 then inr (Left "Fehler") else do
inl $ put (st - 1)
return $ st^2 + st + 1
runM :: Int -> M a -> IO a
runM st m = newIORef st >>= \ref -> elim (embedState ref) embedErr m
embedState :: IORef s -> State s a -> IO a
embedState ref m = do
st <- readIORef ref
let (x,st') = runState m st
writeIORef ref st'
return x
embedErr :: (Show e) => Err e a -> IO a
embedErr (Left e) = putStrLn ("Fehler: " ++ show e) >> exitFailure
embedErr (Right x) = return x