File: PoorMansConcurrency.hs

package info (click to toggle)
haskell-operational 0.2.3.2-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 132 kB
  • sloc: haskell: 441; sh: 78; makefile: 2
file content (64 lines) | stat: -rw-r--r-- 2,201 bytes parent folder | download
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
{------------------------------------------------------------------------------
    Control.Monad.Operational
    
    Example:
    Koen Claessen's Poor Man's Concurrency Monad
    http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.39.8039

------------------------------------------------------------------------------}
{-# LANGUAGE GADTs, Rank2Types #-}
module PoorMansConcurrency where

import Control.Monad
import Control.Monad.Operational
import Control.Monad.Trans hiding (lift)

{------------------------------------------------------------------------------
    A concurrency monad runs several processes in parallel
    and supports two primitive operations

        fork  -- fork a new process
        stop  -- halt the current one
    
    We want this to be a monad transformer, so we also need a function  lift
    This time, however, we cannot use the monad transformer version  ProgramT
    because this will leave no room for interleaving different computations
    of the base monad.
------------------------------------------------------------------------------}
data ProcessI m a where
    Lift :: m a -> ProcessI m a
    Stop :: ProcessI m a
    Fork :: Process m () -> ProcessI m ()


type Process m a = Program (ProcessI m) a

stop = singleton Stop
fork = singleton . Fork
lift = singleton . Lift

-- interpreter
runProcess :: Monad m => Process m a -> m ()
runProcess m = schedule [m]
    where
    schedule :: Monad m => [Process m a] -> m ()
    schedule (x:xs) = run (view x) xs

    run :: Monad m => ProgramView (ProcessI m) a -> [Process m a] -> m ()
    run (Return _)      xs = return ()                 -- process finished
    run (Lift m :>>= k) xs = m >>= \a ->               -- switch process
                             schedule (xs ++ [k a])
    run (Stop   :>>= k) xs = schedule xs               -- process halts
    run (Fork p :>>= k) xs = schedule (xs ++ [x2,x1])  -- fork new process
        where x1 = k (); x2 = p >>= k

-- example
--      > runProcess example   -- warning: runs indefinitely
example :: Process IO ()
example = do
        write "Start!"
        fork (loop "fish")
        loop "cat"

write  = lift . putStr
loop s = write s >> loop s