freer-0.2.2.1: examples/src/Coroutine.hs
module Coroutine where
-- import Control.Monad.Freer.Coroutine
{-
-- First example of coroutines
yieldInt :: Member (Yield Int ()) r => Int -> Eff r ()
yieldInt = yield
th1 :: Member (Yield Int ()) r => Eff r ()
th1 = yieldInt 1 >> yieldInt 2
c1 = runTrace (loop =<< runC th1)
where loop (Y x k) = trace (show (x::Int)) >> k () >>= loop
loop Done = trace "Done"
{-
1
2
Done
-}
-- Add dynamic variables
-- The code is essentially the same as that in transf.hs (only added
-- a type specializtion on yield). The inferred signature is different though.
-- Before it was
-- th2 :: MonadReader Int m => CoT Int m ()
-- Now it is more general:
th2 :: (Member (Yield Int ()) r, Member (Reader Int) r) => Eff r ()
th2 = ask >>= yieldInt >> (ask >>= yieldInt)
-- Code is essentially the same as in transf.hs; no liftIO though
c2 = runTrace $ runReader (loop =<< runC th2) (10::Int)
where loop (Y x k) = trace (show (x::Int)) >> k () >>= loop
loop Done = trace "Done"
{-
10
10
Done
-}
-- locally changing the dynamic environment for the suspension
c21 = runTrace $ runReader (loop =<< runC th2) (10::Int)
where loop (Y x k) = trace (show (x::Int)) >> local (+(1::Int)) (k ()) >>= loop
loop Done = trace "Done"
{-
10
11
Done
-}
-- Real example, with two sorts of local rebinding
th3 :: (Member (Yield Int ()) r, Member (Reader Int) r) => Eff r ()
th3 = ay >> ay >> local (+(10::Int)) (ay >> ay)
where ay = ask >>= yieldInt
c3 = runTrace $ runReader (loop =<< runC th3) (10::Int)
where loop (Y x k) = trace (show (x::Int)) >> k () >>= loop
loop Done = trace "Done"
{-
10
10
20
20
Done
-}
-- locally changing the dynamic environment for the suspension
c31 = runTrace $ runReader (loop =<< runC th3) (10::Int)
where loop (Y x k) = trace (show (x::Int)) >> local (+(1::Int)) (k ()) >>= loop
loop Done = trace "Done"
{-
10
11
21
21
Done
-}
-- The result is exactly as expected and desired: the coroutine shares the
-- dynamic environment with its parent; however, when the environment
-- is locally rebound, it becomes private to coroutine.
-- We now make explicit that the client computation, run by th4,
-- is abstract. We abstract it out of th4
c4 = runTrace $ runReader (loop =<< runC (th4 client)) (10::Int)
where loop (Y x k) = trace (show (x::Int)) >> local (+(1::Int)) (k ()) >>= loop
loop Done = trace "Done"
-- cl, client, ay are monomorphic bindings
th4 cl = cl >> local (+(10::Int)) cl
client = ay >> ay
ay = ask >>= yieldInt
{-
10
11
21
21
Done
-}
-- Even more dynamic example
c5 = runTrace $ runReader (loop =<< runC (th client)) (10::Int)
where loop (Y x k) = trace (show (x::Int)) >> local (\y->x+1) (k ()) >>= loop
loop Done = trace "Done"
-- cl, client, ay are monomorphic bindings
client = ay >> ay >> ay
ay = ask >>= yieldInt
-- There is no polymorphic recursion here
th cl = do
cl
v <- ask
(if v > (20::Int) then id else local (+(5::Int))) cl
if v > (20::Int) then return () else local (+(10::Int)) (th cl)
{-
10
11
12
18
18
18
29
29
29
29
29
29
Done
-}
-- And even more
c7 = runTrace $
runReader (runReader (loop =<< runC (th client)) (10::Int)) (1000::Double)
where loop (Y x k) = trace (show (x::Int)) >>
local (\y->fromIntegral (x+1)::Double) (k ()) >>= loop
loop Done = trace "Done"
-- cl, client, ay are monomorphic bindings
client = ay >> ay >> ay
ay = ask >>= \x -> ask >>=
\y -> yieldInt (x + round (y::Double))
-- There is no polymorphic recursion here
th cl = do
cl
v <- ask
(if v > (20::Int) then id else local (+(5::Int))) cl
if v > (20::Int) then return () else local (+(10::Int)) (th cl)
{-
1010
1021
1032
1048
1064
1080
1101
1122
1143
1169
1195
1221
1252
1283
1314
1345
1376
1407
Done
-}
c7' = runTrace $
runReader (runReader (loop =<< runC (th client)) (10::Int)) (1000::Double)
where loop (Y x k) = trace (show (x::Int)) >>
local (\y->fromIntegral (x+1)::Double) (k ()) >>= loop
loop Done = trace "Done"
-- cl, client, ay are monomorphic bindings
client = ay >> ay >> ay
ay = ask >>= \x -> ask >>=
\y -> yieldInt (x + round (y::Double))
-- There is no polymorphic recursion here
th cl = do
cl
v <- ask
(if v > (20::Int) then id else local (+(5::Double))) cl
if v > (20::Int) then return () else local (+(10::Int)) (th cl)
{-
1010
1021
1032
1048
1048
1048
1069
1090
1111
1137
1137
1137
1168
1199
1230
1261
1292
1323
Done
-}
-}