packages feed

chp 2.1.0.1 → 2.2.0

raw patch · 20 files changed

+577/−611 lines, 20 filesdep −loop-whiledep −mtlPVP ok

version bump matches the API change (PVP)

Dependencies removed: loop-while, mtl

API changes (from Hackage documentation)

- Control.Concurrent.CHP.Channels.Creation: class ChannelTuple t
- Control.Concurrent.CHP.Channels.Creation: instance (Channel r w) => ChannelTuple (Chan r w a, Chan r w a)
- Control.Concurrent.CHP.Channels.Creation: instance (Channel r w) => ChannelTuple (Chan r w a, Chan r w a, Chan r w a)
- Control.Concurrent.CHP.Channels.Creation: instance (Channel r w) => ChannelTuple (Chan r w a, Chan r w a, Chan r w a, Chan r w a)
- Control.Concurrent.CHP.Channels.Creation: instance (Channel r w) => ChannelTuple (Chan r w a, Chan r w a, Chan r w a, Chan r w a, Chan r w a)
- Control.Concurrent.CHP.Channels.Creation: instance (Channel r w) => ChannelTuple (Chan r w a, Chan r w a, Chan r w a, Chan r w a, Chan r w a, Chan r w a)
- Control.Concurrent.CHP.Channels.Creation: newChannels :: (ChannelTuple t, MonadCHP m) => m t
- Control.Concurrent.CHP.Clocks: instance (Ord time) => Enrollable Clock time
- Control.Concurrent.CHP.Clocks: instance (Ord time) => Poisonable (Enrolled Clock time)
- Control.Concurrent.CHP.Parallel: instance (Monad m) => Monad (ForkingT m)
- Control.Concurrent.CHP.Parallel: instance (MonadCHP m) => MonadCHP (ForkingT m)
- Control.Concurrent.CHP.Parallel: instance (MonadIO m) => MonadIO (ForkingT m)
- Control.Concurrent.CHP.Parallel: instance MonadTrans ForkingT
- Control.Concurrent.CHP.Traces.CSP: instance (Ord u) => Show (CSPTrace u)
- Control.Concurrent.CHP.Traces.Structural: instance (Eq a) => Eq (EventHierarchy a)
- Control.Concurrent.CHP.Traces.Structural: instance (Ord u) => Show (StructuralTrace u)
- Control.Concurrent.CHP.Traces.Structural: instance (Read a) => Read (EventHierarchy a)
- Control.Concurrent.CHP.Traces.Structural: instance (Show a) => Show (EventHierarchy a)
- Control.Concurrent.CHP.Traces.VCR: instance (Ord u) => Show (VCRTrace u)
+ Control.Concurrent.CHP.Clocks: instance Ord time => Enrollable Clock time
+ Control.Concurrent.CHP.Clocks: instance Ord time => Poisonable (Enrolled Clock time)
+ Control.Concurrent.CHP.Monad: foreverP :: CHP a -> CHP b
+ Control.Concurrent.CHP.Monad: liftIO_CHP :: IO a -> CHP a
+ Control.Concurrent.CHP.Monad: liftIO_CHP' :: String -> IO a -> CHP a
+ Control.Concurrent.CHP.Monad: process :: String -> a -> a
+ Control.Concurrent.CHP.Monad: subProcess :: String -> a -> a
+ Control.Concurrent.CHP.Parallel: instance Monad m => Monad (ForkingT m)
+ Control.Concurrent.CHP.Parallel: instance MonadCHP m => MonadCHP (ForkingT m)
+ Control.Concurrent.CHP.Parallel: liftForking :: Monad m => m a -> ForkingT m a
+ Control.Concurrent.CHP.Traces.CSP: instance Ord u => Show (CSPTrace u)
+ Control.Concurrent.CHP.Traces.Structural: instance Eq a => Eq (EventHierarchy a)
+ Control.Concurrent.CHP.Traces.Structural: instance Ord u => Show (StructuralTrace u)
+ Control.Concurrent.CHP.Traces.Structural: instance Read a => Read (EventHierarchy a)
+ Control.Concurrent.CHP.Traces.Structural: instance Show a => Show (EventHierarchy a)
+ Control.Concurrent.CHP.Traces.VCR: instance Ord u => Show (VCRTrace u)
- Control.Concurrent.CHP.Barriers: syncAndWaitForPhase :: (Eq phase) => phase -> Enrolled PhasedBarrier phase -> CHP ()
+ Control.Concurrent.CHP.Barriers: syncAndWaitForPhase :: Eq phase => phase -> Enrolled PhasedBarrier phase -> CHP ()
- Control.Concurrent.CHP.Barriers: waitForPhase :: (Eq phase) => phase -> Enrolled PhasedBarrier phase -> CHP ()
+ Control.Concurrent.CHP.Barriers: waitForPhase :: Eq phase => phase -> Enrolled PhasedBarrier phase -> CHP ()
- Control.Concurrent.CHP.Channels.BroadcastReduce: anyToManyChannel :: (MonadCHP m) => m (AnyToManyChannel a)
+ Control.Concurrent.CHP.Channels.BroadcastReduce: anyToManyChannel :: MonadCHP m => m (AnyToManyChannel a)
- Control.Concurrent.CHP.Channels.BroadcastReduce: anyToManyChannel' :: (MonadCHP m) => ChanOpts a -> m (AnyToManyChannel a)
+ Control.Concurrent.CHP.Channels.BroadcastReduce: anyToManyChannel' :: MonadCHP m => ChanOpts a -> m (AnyToManyChannel a)
- Control.Concurrent.CHP.Channels.BroadcastReduce: oneToManyChannel :: (MonadCHP m) => m (OneToManyChannel a)
+ Control.Concurrent.CHP.Channels.BroadcastReduce: oneToManyChannel :: MonadCHP m => m (OneToManyChannel a)
- Control.Concurrent.CHP.Channels.BroadcastReduce: oneToManyChannel' :: (MonadCHP m) => ChanOpts a -> m (OneToManyChannel a)
+ Control.Concurrent.CHP.Channels.BroadcastReduce: oneToManyChannel' :: MonadCHP m => ChanOpts a -> m (OneToManyChannel a)
- Control.Concurrent.CHP.Channels.Communication: extReadChannel :: (ReadableChannel chanEnd) => chanEnd a -> (a -> CHP b) -> CHP b
+ Control.Concurrent.CHP.Channels.Communication: extReadChannel :: ReadableChannel chanEnd => chanEnd a -> (a -> CHP b) -> CHP b
- Control.Concurrent.CHP.Channels.Communication: extWriteChannel :: (WriteableChannel chanEnd) => chanEnd a -> CHP a -> CHP ()
+ Control.Concurrent.CHP.Channels.Communication: extWriteChannel :: WriteableChannel chanEnd => chanEnd a -> CHP a -> CHP ()
- Control.Concurrent.CHP.Channels.Communication: extWriteChannel' :: (WriteableChannel chanEnd) => chanEnd a -> CHP (a, b) -> CHP b
+ Control.Concurrent.CHP.Channels.Communication: extWriteChannel' :: WriteableChannel chanEnd => chanEnd a -> CHP (a, b) -> CHP b
- Control.Concurrent.CHP.Channels.Communication: readChannel :: (ReadableChannel chanEnd) => chanEnd a -> CHP a
+ Control.Concurrent.CHP.Channels.Communication: readChannel :: ReadableChannel chanEnd => chanEnd a -> CHP a
- Control.Concurrent.CHP.Channels.Communication: writeChannel :: (WriteableChannel chanEnd) => chanEnd a -> a -> CHP ()
+ Control.Concurrent.CHP.Channels.Communication: writeChannel :: WriteableChannel chanEnd => chanEnd a -> a -> CHP ()
- Control.Concurrent.CHP.Channels.Communication: writeValue :: (WriteableChannel chanEnd) => a -> chanEnd a -> CHP ()
+ Control.Concurrent.CHP.Channels.Communication: writeValue :: WriteableChannel chanEnd => a -> chanEnd a -> CHP ()
- Control.Concurrent.CHP.Channels.Creation: chanLabel :: (Show a) => String -> ChanOpts a
+ Control.Concurrent.CHP.Channels.Creation: chanLabel :: Show a => String -> ChanOpts a
- Control.Concurrent.CHP.Channels.Creation: labelChannel :: (MonadCHP m) => Chan r w a -> String -> m ()
+ Control.Concurrent.CHP.Channels.Creation: labelChannel :: MonadCHP m => Chan r w a -> String -> m ()
- Control.Concurrent.CHP.Channels.Creation: sameChannel :: (Channel r w) => r a -> w a -> Bool
+ Control.Concurrent.CHP.Channels.Creation: sameChannel :: Channel r w => r a -> w a -> Bool
- Control.Concurrent.CHP.Channels.Synonyms: anyToAnyChannel :: (MonadCHP m) => m (AnyToAnyChannel a)
+ Control.Concurrent.CHP.Channels.Synonyms: anyToAnyChannel :: MonadCHP m => m (AnyToAnyChannel a)
- Control.Concurrent.CHP.Channels.Synonyms: anyToAnyChannel' :: (MonadCHP m) => ChanOpts a -> m (AnyToAnyChannel a)
+ Control.Concurrent.CHP.Channels.Synonyms: anyToAnyChannel' :: MonadCHP m => ChanOpts a -> m (AnyToAnyChannel a)
- Control.Concurrent.CHP.Channels.Synonyms: anyToOneChannel :: (MonadCHP m) => m (AnyToOneChannel a)
+ Control.Concurrent.CHP.Channels.Synonyms: anyToOneChannel :: MonadCHP m => m (AnyToOneChannel a)
- Control.Concurrent.CHP.Channels.Synonyms: anyToOneChannel' :: (MonadCHP m) => ChanOpts a -> m (AnyToOneChannel a)
+ Control.Concurrent.CHP.Channels.Synonyms: anyToOneChannel' :: MonadCHP m => ChanOpts a -> m (AnyToOneChannel a)
- Control.Concurrent.CHP.Channels.Synonyms: oneToAnyChannel :: (MonadCHP m) => m (OneToAnyChannel a)
+ Control.Concurrent.CHP.Channels.Synonyms: oneToAnyChannel :: MonadCHP m => m (OneToAnyChannel a)
- Control.Concurrent.CHP.Channels.Synonyms: oneToAnyChannel' :: (MonadCHP m) => ChanOpts a -> m (OneToAnyChannel a)
+ Control.Concurrent.CHP.Channels.Synonyms: oneToAnyChannel' :: MonadCHP m => ChanOpts a -> m (OneToAnyChannel a)
- Control.Concurrent.CHP.Channels.Synonyms: oneToOneChannel :: (MonadCHP m) => m (OneToOneChannel a)
+ Control.Concurrent.CHP.Channels.Synonyms: oneToOneChannel :: MonadCHP m => m (OneToOneChannel a)
- Control.Concurrent.CHP.Channels.Synonyms: oneToOneChannel' :: (MonadCHP m) => ChanOpts a -> m (OneToOneChannel a)
+ Control.Concurrent.CHP.Channels.Synonyms: oneToOneChannel' :: MonadCHP m => ChanOpts a -> m (OneToOneChannel a)
- Control.Concurrent.CHP.Clocks: data (Ord time) => Clock time
+ Control.Concurrent.CHP.Clocks: data Ord time => Clock time
- Control.Concurrent.CHP.Enroll: enroll :: (Enrollable b z) => b z -> (Enrolled b z -> CHP a) -> CHP a
+ Control.Concurrent.CHP.Enroll: enroll :: Enrollable b z => b z -> (Enrolled b z -> CHP a) -> CHP a
- Control.Concurrent.CHP.Enroll: enrollAll :: (Enrollable b p) => CHP (b p) -> [Enrolled b p -> CHP a] -> CHP [a]
+ Control.Concurrent.CHP.Enroll: enrollAll :: Enrollable b p => CHP (b p) -> [Enrolled b p -> CHP a] -> CHP [a]
- Control.Concurrent.CHP.Enroll: enrollAllT :: (Enrollable b p) => ([a] -> CHP c) -> CHP (b p) -> [Enrolled b p -> a] -> CHP c
+ Control.Concurrent.CHP.Enroll: enrollAllT :: Enrollable b p => ([a] -> CHP c) -> CHP (b p) -> [Enrolled b p -> a] -> CHP c
- Control.Concurrent.CHP.Enroll: enrollAll_ :: (Enrollable b p) => CHP (b p) -> [Enrolled b p -> CHP a] -> CHP ()
+ Control.Concurrent.CHP.Enroll: enrollAll_ :: Enrollable b p => CHP (b p) -> [Enrolled b p -> CHP a] -> CHP ()
- Control.Concurrent.CHP.Enroll: enrollList :: (Enrollable b p) => [b p] -> ([Enrolled b p] -> CHP a) -> CHP a
+ Control.Concurrent.CHP.Enroll: enrollList :: Enrollable b p => [b p] -> ([Enrolled b p] -> CHP a) -> CHP a
- Control.Concurrent.CHP.Enroll: enrollOneMany :: (Enrollable b p) => ([Enrolled b p] -> CHP a) -> [(CHP (b p), Enrolled b p -> CHP c)] -> CHP (a, [c])
+ Control.Concurrent.CHP.Enroll: enrollOneMany :: Enrollable b p => ([Enrolled b p] -> CHP a) -> [(CHP (b p), Enrolled b p -> CHP c)] -> CHP (a, [c])
- Control.Concurrent.CHP.Enroll: furtherEnroll :: (Enrollable b z) => Enrolled b z -> (Enrolled b z -> CHP a) -> CHP a
+ Control.Concurrent.CHP.Enroll: furtherEnroll :: Enrollable b z => Enrolled b z -> (Enrolled b z -> CHP a) -> CHP a
- Control.Concurrent.CHP.Enroll: resign :: (Enrollable b z) => Enrolled b z -> CHP a -> CHP a
+ Control.Concurrent.CHP.Enroll: resign :: Enrollable b z => Enrolled b z -> CHP a -> CHP a
- Control.Concurrent.CHP.Monad: class (MonadIO m) => MonadCHP m
+ Control.Concurrent.CHP.Monad: class Monad m => MonadCHP m
- Control.Concurrent.CHP.Monad: liftCHP :: (MonadCHP m) => CHP a -> m a
+ Control.Concurrent.CHP.Monad: liftCHP :: MonadCHP m => CHP a -> m a
- Control.Concurrent.CHP.Parallel: data (Monad m, MonadCHP m) => ForkingT m a
+ Control.Concurrent.CHP.Parallel: data ForkingT m a
- Control.Concurrent.CHP.Parallel: fork :: (MonadCHP m) => CHP () -> ForkingT m ()
+ Control.Concurrent.CHP.Parallel: fork :: MonadCHP m => CHP () -> ForkingT m ()
- Control.Concurrent.CHP.Parallel: forking :: (MonadCHP m) => ForkingT m a -> m a
+ Control.Concurrent.CHP.Parallel: forking :: MonadCHP m => ForkingT m a -> m a
- Control.Concurrent.CHP.Traces: emptyTrace :: (Trace t) => t u
+ Control.Concurrent.CHP.Traces: emptyTrace :: Trace t => t u
- Control.Concurrent.CHP.Traces: runCHPAndTrace :: (Trace t) => CHP a -> IO (Maybe a, t Unique)
+ Control.Concurrent.CHP.Traces: runCHPAndTrace :: Trace t => CHP a -> IO (Maybe a, t Unique)
- Control.Concurrent.CHP.Traces: structuralToCSP :: (Ord u) => StructuralTrace u -> [CSPTrace u]
+ Control.Concurrent.CHP.Traces: structuralToCSP :: Ord u => StructuralTrace u -> [CSPTrace u]
- Control.Concurrent.CHP.Traces: structuralToVCR :: (Ord u) => StructuralTrace u -> [VCRTrace u]
+ Control.Concurrent.CHP.Traces: structuralToVCR :: Ord u => StructuralTrace u -> [VCRTrace u]
- Control.Concurrent.CHP.Traces: vcrToCSP :: (Eq u) => VCRTrace u -> [CSPTrace u]
+ Control.Concurrent.CHP.Traces: vcrToCSP :: Eq u => VCRTrace u -> [CSPTrace u]

Files

Control/Concurrent/CHP/Alt.hs view
@@ -28,9 +28,8 @@ -- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  --- | A module containing the ALT constructs.  An ALT (a term inherited from--- occam) is a choice between several alternate events.  In CHP, we say that an event--- must support alting to be a valid choice.  Events that /do/ support alting are:+-- | A module containing constructs for choice, or alting.  An ALT (a term inherited from+-- occam) is a choice between several alternate events.  Events that inherently support choice are: -- -- * 'Control.Concurrent.CHP.Monad.skip' --@@ -38,11 +37,11 @@ --  -- * 'Control.Concurrent.CHP.Monad.waitFor' -- --- * Reading from a channel (including extended reads): that is, calls to 'Control.Concurrent.CHP.Channels.readChannel'--- and 'Control.Concurrent.CHP.Channels.extReadChannel'+-- * Reading from a channel (including extended reads): that is, calls to 'Control.Concurrent.CHP.Channels.Communication.readChannel'+-- and 'Control.Concurrent.CHP.Channels.Communication.extReadChannel' -- --- * Writing to a channel (including extended writes): that is, calls to 'Control.Concurrent.CHP.Channels.writeChannel'--- and 'Control.Concurrent.CHP.Channels.extWriteChannel'+-- * Writing to a channel (including extended writes): that is, calls to 'Control.Concurrent.CHP.Channels.Communication.writeChannel'+-- and 'Control.Concurrent.CHP.Channels.Communication.extWriteChannel' --  -- * Synchronising on a barrier (using 'Control.Concurrent.CHP.Barriers.syncBarrier') -- @@ -55,7 +54,8 @@ -- * A call to 'every', which joins together several items (see the documentation -- on 'every'). ----- Examples of events that do /NOT/ support alting are:+-- There are several other events that can occur in CHP; these are assumed to be+-- always-ready when they are included in a choice.  Examples include: -- -- * Enrolling and resigning with a barrier -- @@ -69,60 +69,44 @@ -- -- * Claiming a shared channel (yet...) ----- It is not easily possible to represent this at the type level (while still--- making CHP easy to use).  Therefore it is left to you to not try to alt--- over something that does not support it.  Given how much of the library--- does support alting, that should hopefully be straightforward.+-- * A return statement by itself -- -- Here are some examples of using alting: -- -- * Wait for an integer channel, or 1 second to elapse: ----- > liftM Just (readChannel c) <-> (waitFor 1000000 >> return Nothing)+-- > liftM Just (readChannel c) <|> (waitFor 1000000 >> return Nothing) ----- * Check if a channel is ready, otherwise return immediately.  Note that you must use the--- alt operator with priority here, otherwise your skip guard might be chosen,--- even when the channel is ready.+-- * Check if a channel is ready, otherwise return immediately; this can be done+-- using the 'optional' function from "Control.Applicative": -- --- > liftM Just (readChannel c) </> (skip >> return Nothing)+-- > optional (readChannel c) -- -- * Wait for input from one of two (identically typed) channels -- --- > readChannel c0 <-> readChannel c1+-- > readChannel c0 <|> readChannel c1 -- -- * Check if a channel is ready; if so send, it on, otherwise return immediately: -- --- > (readChannel c >>= writeChannel d) </> skip+-- > (readChannel c >>= writeChannel d) <|> skip -- -- Note that if you wait for a sequential composition: ----- > (readChannel c >>= writeChannel d) <-> (writeChannel e 6 >> readChannel f)+-- > (readChannel c >>= writeChannel d) <|> (writeChannel e 6 >> readChannel f) -- -- This only waits for the first action in both (reading from channel c, or writing -- to channel e), not for all of the actions (as, for example, an STM transaction -- would). module Control.Concurrent.CHP.Alt (alt, (<->), priAlt, (</>), every, every_, (<&>)) where -import Control.Applicative-import Control.Arrow-import Control.Concurrent-import Control.Concurrent.STM-import Control.Monad.Reader-import Data.List-import qualified Data.Map as Map-import Data.Maybe-import Data.Monoid-import qualified Data.Set as Set-import Data.Unique-import System.IO+import Control.Applicative ((<$>), (<|>))+import Data.Monoid (mappend) -import Control.Concurrent.CHP.Base-import Control.Concurrent.CHP.Event-import Control.Concurrent.CHP.Guard-import Control.Concurrent.CHP.Monad-import Control.Concurrent.CHP.Parallel-import Control.Concurrent.CHP.Poison-import Control.Concurrent.CHP.Traces.Base+import Control.Concurrent.CHP.Base (CHP(..), CHP'(..), liftIO_CHP, makeAltable', priAlt, throwPoison, wrapPoison)+import Control.Concurrent.CHP.Guard (Guard(..))+import Control.Concurrent.CHP.Monad (skip)+import Control.Concurrent.CHP.Parallel (runParallel)+import Control.Concurrent.CHP.Poison (WithPoison(..))  -- | An alt between several actions, with arbitrary priority.  The first -- available action is chosen (with an arbitrary choice if many actions are@@ -130,51 +114,6 @@ alt :: [CHP a] -> CHP a alt = priAlt --- | An alt between several actions, with descending priority.  The first--- available action is chosen (biased towards actions nearest the beginning--- of the list), its body run, and its value returned.------ What priority means here is a difficult thing, and in some ways a historical--- artifact.  We can group the guards into three categories:------ 1. synchronisation guards (reading from and writing to channels, and synchronising--- on barriers)------ 2. time-out guards (such as 'Control.Concurrent.CHP.Monad.waitFor')------ 3. dummy guards ('Control.Concurrent.CHP.Monad.skip' and 'Control.Concurrent.CHP.Monad.stop')------ There exists priority when comparing dummy guards to anything else.  So for--- example,------ > priAlt [ skip, x ]------ Will always select the first guard, whereas:------ > priAlt [ x , skip ]------ Is an effective way to poll and see if x is ready, otherwise the 'Control.Concurrent.CHP.Monad.skip' will--- be chosen.  However, there is no priority between synchronisation guards and--- time-out guards.  So the two lines:------ > priAlt [ x, y ]--- > priAlt [ y, x ]------ May have the same or different behaviour (when x and y are not dummy guards),--- there is no guarantee either way.  The reason behind this is that if you ask--- for:------ > priAlt [ readChannel c, writeChannel d 6 ]------ And the process at the other end is asking for:------ > priAlt [ readChannel d, writeChannel c 8 ]------ Whichever channel is chosen by both processes will not satisfy the priority--- at one end (if such priority between channels was supported).-priAlt :: [CHP a] -> CHP a-priAlt = unwrapPoison . priAlt' . map wrapPoison- -- | A useful operator to perform an 'alt'.  This operator is associative, -- and has arbitrary priority.  When you have lots of guards, it is probably easier -- to use the 'alt' function.  'alt' /may/ be more efficent than@@ -187,8 +126,11 @@ -- left-biased).  When you have lots of actions, it is probably easier -- to use the 'priAlt' function.  'priAlt' /may/ be more efficent than -- foldl1 (\<\/\>)+--+-- Since version 2.2.0, this operator is deprecated in favour of the (<|>) operator+-- from the Alternative type-class. (</>) :: CHP a -> CHP a -> CHP a-(</>) a b = priAlt [a,b]+(</>) = (<|>)  infixl </> infixl <->@@ -288,36 +230,31 @@ -- behaviour as x. -- -- Added in version 1.1.0-every :: forall a. [CHP a] -> CHP [a]+every :: [CHP a] -> CHP [a] every [] = skip >> return []-every xs = liftPoison (AltableT (liftM ((:[]) . flip (,) (return True)) $ gs >>= foldM1 merge) (return-   False)) >>= \b -> if b then runParallel (map (unwrapPoison . liftTrace) bodies) else alt [every xs]+every xs = makeAltable' (\tr -> let gs = map fst $ getAltable tr+  in [(foldl1 merge gs, return $ NoPoison ())]) >> wrapped   where-    both :: Either String [(Guard, TraceT IO (WithPoison a))]-    both = mapM (checkSingle . pullOutAltable . wrapPoison) xs-    gs :: Either String [Guard]-    gs = liftM (map fst) both-    bodies = map snd $ fromRight both-    fromRight (Right x) = x-    fromRight _ = error "Reached unreachable code in every; bodies executed after bad guard"+    wrapped = PoisonT $ \t f -> let bodies = map snd $ getAltable t+      in wrapPoison t (runParallel (map wrap bodies)) >>= f -    checkSingle (Left err) = Left err-    checkSingle (Right []) = Left "Bad guard in every"-    checkSingle (Right [x]) = Right x-    checkSingle (Right _) = Left "Alt inside every"+    wrap m = liftIO_CHP m >>= \v -> case v of+      PoisonItem -> throwPoison+      NoPoison x -> return x -    merge :: Guard -> Guard -> Either String Guard-    merge SkipGuard g = return g-    merge g SkipGuard = return g-    merge StopGuard _ = return StopGuard-    merge _ StopGuard = return StopGuard+    getAltable tr = flip map xs $ \x -> case runPoisonT x tr return of+      Altable _ [ga] -> ga+      _ -> error "Bad item in every"++    merge :: Guard -> Guard -> Guard+    merge SkipGuard g = g+    merge g SkipGuard = g+    merge StopGuard _ = StopGuard+    merge _ StopGuard = StopGuard     merge (EventGuard recx actx esx) (EventGuard recy acty esy)-      = return $ EventGuard (\n -> recx n ++ recy n) (actx `mappend` acty) (esx ++ esy)-    merge _ _ = badGuard "merging unsupported guards"+      = EventGuard (\n -> recx n ++ recy n) (actx `mappend` acty) (esx ++ esy)+    merge _ _ = error "every: merging unsupported guards" -    foldM1 :: Monad m => (b -> b -> m b) -> [b] -> m b-    foldM1 f (y:ys) = foldM f y ys-    foldM1 _ _ = error "Reached unreachable code in every; guards empty in non-empty case"  -- | Like 'every' but discards the results. --@@ -330,7 +267,7 @@ -- to join with this operator, it's probably easier to use the 'every' function. -- -- Added in version 1.1.0-(<&>) :: forall a b. CHP a -> CHP b -> CHP (a, b)+(<&>) :: CHP a -> CHP b -> CHP (a, b) (<&>) a b = merge <$> every [Left <$> a, Right <$> b]   where     merge :: [Either a b] -> (a, b)@@ -338,138 +275,4 @@     merge [Right y, Left x] = (x, y)     merge _ = error "Invalid merge possibility in <&>" --- ALTing is implemented as follows in CHP.  The CHP monad has [Int] in its--- state.  When you choose between N events, you form one body, that pulls--- the next number from the head of the state and executes the body for the--- event corresponding to that index.  Nested ALTs prepend to the list.--- So for example, if you choose between:------ > (a <-> b) <-> c------ The overall number corresponding to a is [0,0], b is [0,1], c is [1].  The--- outer choice peels off the head of the list.  On 1 it executes c; on 0 it--- descends to the nested choice, which takes the next number in the list and--- executes a or b given 0 or 1 respectively.------ If an event is poisoned, an integer (of arbitrary value) is /appended/ to--- the list.  Thus when an event-based guard is executed, if the list in the--- state is non-empty, it knows it has been poisoned.------ I did try implementing this in a more functional manner, making each event--- in the monad take [Int] and return the body, rather than using state.  However,--- I had some memory efficiency problems so I went with the state-monad-based--- approach instead. -priAlt' :: forall a. [CHP' (WithPoison a)] -> CHP' (WithPoison a)-priAlt' items-  -- Our guard is a nested guard of all our sub-guards.-  -- Our action-if-not-guard is to do the selection ourselves.-  = AltableT flattenedGuards (selectFromGuards flattenedGuards)-  where-    -- The list of guards without any NestedGuards or StopGuards:-    flattenedGuards :: Either String [(Guard, TraceT IO (WithPoison a))]-    flattenedGuards = liftM (filter (not . isStopGuard . fst)) altStuff-      where-        altStuff :: Either String [(Guard, TraceT IO (WithPoison a))]-        altStuff = liftM concat $ mapM pullOutAltable items---- Performs the select operation on all the guards, and then executes the body-selectFromGuards :: forall a. (Either String [(Guard, TraceT IO (WithPoison a))]) -> TraceT IO (WithPoison a)-selectFromGuards (Left str) =-           let err = "ALTing not supported on given guard: " ++ str-           in liftIO $ do hPutStrLn stderr err-                          ioError $ userError err-selectFromGuards (Right both)-        | null (eventGuards $ map fst both) =-           join $ liftM snd $ liftIO $ waitNormalGuards both Nothing-        | otherwise =-           do let (guards, _bodies) = unzip both-                  earliestReady = findIndex isSkipGuard guards-                  recordAndRun :: WithPoison ([RecordedIndivEvent Unique], TraceT-                    IO (WithPoison a)) -> TraceT IO (WithPoison a)-                  recordAndRun PoisonItem = return PoisonItem-                  recordAndRun (NoPoison (r, m)) = recordEvent r >> m-                  guardsAndRec :: [(Guard, WithPoison ([RecordedIndivEvent Unique], TraceT IO (WithPoison a)))]-                  guardsAndRec = map (second (NoPoison . (,) [])) both-                  getRec :: (SignalValue, Map.Map Unique (Integer, RecordedEventType))-                         -> WithPoison ([RecordedIndivEvent Unique], TraceT IO (WithPoison a))-                  getRec (Signal PoisonItem, _) = PoisonItem-                  getRec (Signal (NoPoison n), m)-                    = case both !! n of-                        (EventGuard recF _ _, body) ->-                          NoPoison (recF (makeLookup m), body)-                        (_, body) -> NoPoison ([], body)-              tv <- liftIO $ newTVarIO Nothing-              pid <- getProcessId-              tr <- ask-              tid <- liftIO myThreadId-              mn <- liftIO . atomically $ do-                      ret <- enableEvents tv (tid, pid)-                        (maybe id take earliestReady $ eventGuards guards)-                        (isNothing earliestReady)-                      either (const $ return ())-                            (\((sigVal,_),es) -> do-                               recordEventLast (nub es) tr-                               case sigVal of-                                 Signal PoisonItem -> return ()-                                 Signal (NoPoison n) ->-                                   let EventGuard _ act _ = guards !! n-                                   in actWhenLast act (Map.fromList $ map (snd *** Set.size) es)-                            )-                            ret-                      return $ either Left (Right . getRec . fst) ret-              case (mn, earliestReady) of-                -- An event -- and we were the last person to arrive:-                -- The event must have been higher priority than any other-                -- ready guards-                (Right r, _) -> recordAndRun r-                -- No events were ready, but there was an available normal-                -- guards.  Re-run the normal guards; at least one will be ready-                (Left _, Just _) ->-                  join $ liftM snd $ liftIO $ waitNormalGuards both Nothing-                -- No events ready, no other guards ready either-                -- Events will have been enabled; wait for everything:-                (Left disable, Nothing) ->-                    do (wasAltingBarrier, pr) <- liftIO $ waitNormalGuards-                         guardsAndRec $ Just $ liftM getRec $ waitAlting tv-                       if wasAltingBarrier-                         then recordAndRun pr -- It was a barrier, all done-                         else-                            -- Another guard fired, but we must check in case-                            -- we have meanwhile been committed to taking an-                            -- event:-                            do mn' <- liftIO . atomically $ disable-                               case mn' of-                                 -- An event overrides our non-event choice:-                                 Just pr' -> recordAndRun $ getRec pr'-                                 -- Go with the original option, no events-                                 -- became ready:-                                 Nothing -> recordAndRun pr--waitAlting :: SignalVar -> STM (SignalValue, Map.Map Unique (Integer, RecordedEventType))-waitAlting tv = do b <- readTVar tv-                   case b of-                     Nothing -> retry-                     Just ns -> return ns--makeLookup :: Map.Map Unique (Integer, RecordedEventType) -> Unique -> (Integer,-  RecordedEventType)-makeLookup m u = fromMaybe (error "CHP: Unique not found in alt") $ Map.lookup u m---- The alting barrier guards:-eventGuards :: [Guard] -> [((SignalValue, STM ()), [Event])]-eventGuards guards = [((Signal $ NoPoison n, actAlways acts), ab)-                     | (n, EventGuard _ acts ab) <- zip [0..] guards]----- Waits for one of the normal (non-alting barrier) guards to be ready,--- or the given transaction to complete-waitNormalGuards :: [(Guard, b)] -> Maybe (STM b) -> IO (Bool, b)-waitNormalGuards guards extra-  = do enabled <- sequence $ mapMaybe enable guards-       atomically $ foldr orElse retry $ maybe id ((:) . liftM ((,) True)) extra $ enabled-  where-    enable :: (Guard, b) -> Maybe (IO (STM (Bool, b)))-    enable (SkipGuard, x) = Just $ return $ return (False, x)-    enable (TimeoutGuard g, x) = Just $ liftM (>> return (False, x)) g-    enable _ = Nothing -- This effectively ignores other guards
Control/Concurrent/CHP/Barriers.hs view
@@ -69,7 +69,7 @@     syncBarrier, getBarrierIdentifier) where  import Control.Concurrent.STM-import Control.Monad.State+import Control.Monad (liftM, unless, when) import Data.Unique  import Control.Concurrent.CHP.Base@@ -93,7 +93,7 @@      -- | Finds out the current phase a barrier is on. currentPhase :: Enrolled PhasedBarrier phase -> CHP phase-currentPhase (Enrolled (Barrier (_, tv, _))) = liftIO $ atomically $ readTVar tv+currentPhase (Enrolled (Barrier (_, tv, _))) = liftSTM $ readTVar tv  repeatUntil :: (Monad m) => (a -> Bool) -> m a -> m () repeatUntil target comp = do x <- comp@@ -172,10 +172,10 @@  -- | Like 'newPhasedBarrier' but allows you to customise the options. newPhasedBarrier' :: phase -> BarOpts phase -> CHP (PhasedBarrier phase)-newPhasedBarrier' ph (BarOpts incPh pri showPh label) = liftPoison $ liftTrace $ do-  tv <- liftIO $ atomically $ newTVar ph-  e <- liftIO $ newBarrierEvent showPh pri tv-  maybe (return ()) (labelEvent e) label+newPhasedBarrier' ph (BarOpts incPh pri showPh label) = getTrace >>= \tr -> liftIO_CHP $ do+  tv <- atomically $ newTVar ph+  e <- newBarrierEvent showPh pri tv+  maybe (return ()) (labelEvent tr e) label   return $ Barrier (e, tv, incPh)  -- | Creates a new barrier with no processes enrolled and labels it in traces
Control/Concurrent/CHP/Base.hs view
@@ -35,19 +35,20 @@  import Control.Applicative import Control.Arrow+import Control.Concurrent (myThreadId, threadDelay) import Control.Concurrent.STM import qualified Control.Exception.Extensible as C-import Control.Monad.Error-import Control.Monad.LoopWhile-import Control.Monad.Reader-import Control.Monad.State-import Control.Monad.Writer+import Control.Monad import Data.Function (on)+import Data.List (findIndex, nub) import qualified Data.Map as Map+import Data.Maybe (fromMaybe, isNothing, mapMaybe)+import qualified Data.Set as Set import Data.Unique import System.IO import qualified Text.PrettyPrint.HughesPJ +import Control.Concurrent.CHP.Event import Control.Concurrent.CHP.Guard import Control.Concurrent.CHP.Poison import Control.Concurrent.CHP.ProcessId@@ -57,9 +58,6 @@ -- Types: -- ====== --- | An internal dummy type for poison errors-newtype PoisonError = PoisonError ()- -- | An enrolled wrapper for barriers that shows at the type-level whether -- you are enrolled on a barrier.  Enrolled Barriers should never be passed -- to two (or more) processes running in parallel; if two processes synchronise@@ -70,18 +68,43 @@ -- 'Control.Concurrent.CHP.Monad.runCHP' and -- 'Control.Concurrent.CHP.Monad.runCHP_' to execute programs in this -- monad.-newtype CHP a = PoisonT (ErrorT PoisonError CHP' a)-  deriving (Functor, Monad, MonadIO)+--+-- The Alternative instance was added in version 2.2.0.+newtype CHP a = PoisonT {runPoisonT :: forall b. TraceStore -> (a -> CHP' b) -> CHP' b}+--  deriving (Functor, Monad, MonadIO) +instance Functor CHP where+  fmap f m = PoisonT $ \t c -> runPoisonT m t (c . f)++instance Monad CHP where+  return a = PoisonT $ const ($ a)+  m >>= k  = PoisonT $ \t c -> runPoisonT m t (\a -> runPoisonT (k a) t c)+             instance Applicative CHP where   pure = return   (<*>) = ap -data CHP' a = AltableTRet a | AltableT {+instance Alternative CHP where+  empty = stop+  a <|> b = priAlt [a, b]+  -- Like the default definition but makes clear+  -- which the leading action is:+--  some p = do x <- p+--              xs <- many p+--              return (x : xs)++-- | An implementation of liftIO for the CHP monad; this function lifts IO actions+-- into the CHP monad.+--+-- Added in version 2.2.0.+liftIO_CHP :: IO a -> CHP a+liftIO_CHP m = PoisonT $ const $ \f -> (Standard (liftM NoPoison m) >>= f)++data CHP' a = Return a    -- The guard, and body to execute after the guard-  getAltable :: Either String [(Guard, TraceT IO a)],+  | Altable TraceStore [(Guard, IO (WithPoison a))]   -- The body to execute without a guard-  getStandard :: TraceT IO a }+  | Standard (IO (WithPoison a))  -- ======== -- Classes:@@ -90,7 +113,7 @@ -- | A monad transformer class that is very similar to 'MonadIO'.  This can be -- useful if you want to add monad transformers (such as 'StateT', 'ReaderT') on -- top of the 'CHP' monad.-class MonadIO m => MonadCHP m where+class Monad m => MonadCHP m where   liftCHP :: CHP a -> m a  -- | A class representing a type of trace.  The main useful function is 'runCHPAndTrace',@@ -127,32 +150,31 @@ -- Functions:  -- ========== -pullOutStandard :: CHP' a -> TraceT IO a-pullOutStandard m = case m of-  AltableTRet x -> return x-  AltableT _ st -> st+makeAltable :: [(Guard, IO (WithPoison a))] -> CHP a+makeAltable gas = PoisonT $ \t f -> Altable t (map (second (&>>= pullOutStandard . f)) gas) -pullOutAltable :: CHP' a -> Either String [(Guard, TraceT IO a)]-pullOutAltable m = case m of-  AltableTRet _ -> badGuard "return"-  AltableT alt _ -> alt+makeAltable' :: (TraceStore -> [(Guard, IO (WithPoison a))]) -> CHP a+makeAltable' gas = PoisonT $ \t f -> Altable t (map (second (&>>= pullOutStandard . f)) (gas t)) -liftTrace :: TraceT IO a -> CHP' a-liftTrace = AltableT (badGuard "lifted action")+pullOutStandard :: CHP' a -> IO (WithPoison a)+pullOutStandard (Return x) = return (NoPoison x)+pullOutStandard (Altable tr gas) = selectFromGuards tr gas+pullOutStandard (Standard m) = m -wrapPoison :: CHP a -> CHP' (WithPoison a)-wrapPoison (PoisonT m) = either (const PoisonItem) NoPoison <$> runErrorT m+wrapPoison :: TraceStore -> CHP a -> CHP' a+wrapPoison t (PoisonT m) = m t return -unwrapPoison :: CHP' (WithPoison a) -> CHP a-unwrapPoison m = PoisonT (lift m) >>= checkPoison+--unwrapPoison :: (TraceStore -> CHP' a) -> CHP a+--unwrapPoison m = PoisonT $ \t f -> m t >>= f +   -- | Checks for poison, and either returns the value, or throws a poison exception checkPoison :: WithPoison a -> CHP a checkPoison (NoPoison x) = return x-checkPoison PoisonItem = PoisonT $ throwError $ PoisonError ()+checkPoison PoisonItem = PoisonT $ \_ _ -> Standard $ return PoisonItem -liftPoison :: CHP' a -> CHP a-liftPoison = PoisonT . lift+liftPoison :: (TraceStore -> CHP' a) -> CHP a+liftPoison m = PoisonT ((>>=) . m)  -- | Throws a poison exception. throwPoison :: CHP a@@ -167,8 +189,16 @@ -- does so).  If you want to rethrow (and actually, you'll find you usually -- do), use 'onPoisonRethrow' onPoisonTrap :: CHP a -> CHP a -> CHP a-onPoisonTrap (PoisonT body) (PoisonT handler) = PoisonT $ body `catchError` (const handler)+onPoisonTrap (PoisonT body) (PoisonT handler)+  = PoisonT $ \t f ->+     let trap PoisonItem = pullOutStandard $ handler t f+         trap (NoPoison x) = pullOutStandard $ f x in+    case body t return of+      Return x -> f x+      Altable tr gas -> Altable tr (map (second (>>= trap)) gas)+      Standard m -> Standard $ m >>= trap + -- | Like 'onPoisonTrap', this function allows you to provide a handler --  for poison.  The difference with this function is that even if the --  poison handler does not throw, the poison exception will always be@@ -179,35 +209,36 @@ -- > foo `onPoisonRethrow` throwPoison -- > foo `onPoisonRethrow` return () onPoisonRethrow :: CHP a -> CHP () -> CHP a-onPoisonRethrow (PoisonT body) (PoisonT handler) = PoisonT $-  body `catchError` (\err -> handler >> throwError err)+onPoisonRethrow (PoisonT body) (PoisonT handler)+  = PoisonT $ \t f ->+     let handle PoisonItem = PoisonItem <$ (pullOutStandard $ handler t return)+         handle (NoPoison x) = pullOutStandard $ f x in+    case body t return of+      Return x -> f x+      Altable tr gas -> Altable tr (map (second (>>= handle)) gas)+      Standard m -> Standard $ m >>= handle  -- | Poisons all the given items.  A handy shortcut for @mapM_ poison@. poisonAll :: (Poisonable c, MonadCHP m) => [c] -> m () poisonAll = mapM_ poison +getTrace :: CHP TraceStore+getTrace = PoisonT (flip ($)) -liftSTM :: MonadIO m => STM a -> m a-liftSTM = liftIO . atomically+liftSTM :: STM a -> CHP a+liftSTM = liftIO_CHP . atomically -getProcessId :: TraceT IO ProcessId-getProcessId = do x <- ask-                  case x of-                    Trace (pid,_,_) -> return pid-                    NoTrace pid -> return pid+getProcessId :: TraceStore -> ProcessId+getProcessId (Trace (pid,_,_)) = pid+getProcessId (NoTrace pid) = pid -wrapProcess :: CHP a -> (CHP' (Either PoisonError a) -> IO (Either PoisonError a)) -> IO (Maybe (Either () a))-wrapProcess (PoisonT proc) unwrapInner-  = do let inner = runErrorT proc-       x <- liftM Just (unwrapInner inner) `C.catches` allHandlers-       case x of-         Nothing -> return Nothing-         Just (Left _) -> return $ Just $ Left ()-         Just (Right y) -> return $ Just $ Right y+wrapProcess :: CHP a -> TraceStore -> (CHP' a -> IO (WithPoison a)) -> IO (Maybe (WithPoison a))+wrapProcess (PoisonT proc) t unwrapInner+  = (Just <$> unwrapInner (proc t return)) `C.catches` allHandlers   where     response :: C.Exception e => e -> IO (Maybe a)-    response x = liftIO (hPutStrLn stderr $ "(CHP) Thread terminated with: " ++ show x)-                   >> return Nothing+    response x = do hPutStrLn stderr $ "(CHP) Thread terminated with: " ++ show x+                    return Nothing      allHandlers = [C.Handler (response :: C.IOException -> IO (Maybe a))                   ,C.Handler (response :: C.AsyncException -> IO (Maybe a))@@ -222,15 +253,11 @@  runCHPProgramWith :: TraceStore -> CHP a -> IO (Maybe a) runCHPProgramWith start p-  = do r <- wrapProcess p run+  = do r <- wrapProcess p start pullOutStandard        case r of-         Nothing -> return Nothing-         Just (Left _) -> return Nothing-         Just (Right x) -> return (Just x)-  where-    run :: CHP' (Either PoisonError a) -> IO (Either PoisonError a)-    run = flip runReaderT start . pullOutStandard-    --run m = runStateT ({-liftM (either (const Nothing) Just) $ -} pullOutStandard m) start+         Nothing -> putStrLn "Deadlock" >> return Nothing+         Just PoisonItem -> putStrLn "Uncaught Poison" >> return Nothing+         Just (NoPoison x) -> return (Just x)  runCHPProgramWith' :: SubTraceStore -> (ChannelLabels Unique -> IO t) -> CHP a -> IO (Maybe a, t) runCHPProgramWith' subStart f p@@ -283,41 +310,207 @@ -- Instances:  -- ========== -instance Error PoisonError where-  noMsg = PoisonError ()--instance (Error e, MonadCHP m) => MonadCHP (ErrorT e m) where-  liftCHP = lift . liftCHP--instance MonadCHP m => MonadCHP (ReaderT r m) where-  liftCHP = lift . liftCHP--instance MonadCHP m => MonadCHP (StateT s m) where-  liftCHP = lift . liftCHP--instance (Monoid w, MonadCHP m) => MonadCHP (WriterT w m) where-  liftCHP = lift . liftCHP- instance MonadCHP CHP where   liftCHP = id -instance MonadCHP m => MonadCHP (LoopWhileT m) where-  liftCHP = lift . liftCHP- -- The monad is lazy, and very similar to the writer monad instance Monad CHP' where   -- m :: AltableT g m a   -- f :: a -> AltableT g m b   m >>= f = case m of-             AltableTRet x -> f x-             AltableT altBody nonAlt ->-              let altBody' = liftM (map $ second (>>= pullOutStandard . f)) altBody-                  nonAlt' = nonAlt >>= pullOutStandard . f-              in AltableT altBody' nonAlt'-  return = AltableTRet+             Return x -> f x+             Altable tr altBody -> Altable tr $ map (second (&>>= pullOutStandard . f)) altBody+             Standard s -> Standard $ s &>>= pullOutStandard . f+  return = Return  instance Functor CHP' where   fmap = liftM -instance MonadIO CHP' where-  liftIO = liftTrace . liftIO+infixr 8 &>>=+(&>>=) :: IO (WithPoison a) -> (a -> IO (WithPoison b)) -> IO (WithPoison b)+(&>>=) m f = do v <- m+                case v of+                  PoisonItem -> return PoisonItem+                  NoPoison x -> f x+++-- ====+-- Alt:+-- ====++-- Performs the select operation on all the guards, and then executes the body+selectFromGuards :: forall a. TraceStore -> [(Guard, IO (WithPoison a))] -> IO (WithPoison a)+selectFromGuards tr items+  | null (eventGuards guards)+     = join $ liftM snd $ waitNormalGuards items Nothing+  | otherwise = do+      tv <- newTVarIO Nothing+      tid <- myThreadId+      mn <- atomically $ do+              ret <- enableEvents tv (tid, pid)+                (maybe id take earliestReady $ eventGuards guards)+                (isNothing earliestReady)+              either (const $ return ()) whenLast ret+              return $ either Left (Right . getRec . fst) ret+      case (mn, earliestReady) of+        -- An event -- and we were the last person to arrive:+        -- The event must have been higher priority than any other+        -- ready guards+        (Right r, _) -> recordAndRun r+        -- No events were ready, but there was an available normal+        -- guards.  Re-run the normal guards; at least one will be ready+        (Left _, Just _) ->+          join $ liftM snd $ waitNormalGuards items Nothing+        -- No events ready, no other guards ready either+        -- Events will have been enabled; wait for everything:+        (Left disable, Nothing) ->+            do (wasAltingBarrier, pr) <- waitNormalGuards+                 guardsAndRec $ Just $ liftM getRec $ waitAlting tv+               if wasAltingBarrier+                 then recordAndRun pr -- It was a barrier, all done+                 else+                    -- Another guard fired, but we must check in case+                    -- we have meanwhile been committed to taking an+                    -- event:+                    do mn' <- atomically $ disable+                       case mn' of+                         -- An event overrides our non-event choice:+                         Just pr' -> recordAndRun $ getRec pr'+                         -- Go with the original option, no events+                         -- became ready:+                         Nothing -> recordAndRun pr+  where+    guards = map fst items+    earliestReady = findIndex isSkipGuard guards++    recordAndRun :: WithPoison ([RecordedIndivEvent Unique], IO (WithPoison a)) -> IO (WithPoison a)+    recordAndRun PoisonItem = return PoisonItem+    recordAndRun (NoPoison (r, m)) = recordEvent r tr >> m++    guardsAndRec :: [(Guard, WithPoison ([RecordedIndivEvent Unique], IO (WithPoison a)))]+    guardsAndRec = map (second (NoPoison . (,) [])) items++    getRec :: (SignalValue, Map.Map Unique (Integer, RecordedEventType))+           -> WithPoison ([RecordedIndivEvent Unique], IO (WithPoison a))+    getRec (Signal PoisonItem, _) = PoisonItem+    getRec (Signal (NoPoison n), m)+      = case items !! n of+          (EventGuard recF _ _, body) ->+            NoPoison (recF (makeLookup m), body)+          (_, body) -> NoPoison ([], body)++    whenLast ((sigVal,_),es)+      = do recordEventLast (nub es) tr+           case sigVal of+             Signal PoisonItem -> return ()+             Signal (NoPoison n) ->+               let EventGuard _ act _ = guards !! n+               in actWhenLast act (Map.fromList $ map (snd *** Set.size) es)++    pid = getProcessId tr++waitAlting :: SignalVar -> STM (SignalValue, Map.Map Unique (Integer, RecordedEventType))+waitAlting tv = do b <- readTVar tv+                   case b of+                     Nothing -> retry+                     Just ns -> return ns++makeLookup :: Map.Map Unique (Integer, RecordedEventType) -> Unique -> (Integer,+  RecordedEventType)+makeLookup m u = fromMaybe (error "CHP: Unique not found in alt") $ Map.lookup u m++-- The alting barrier guards:+eventGuards :: [Guard] -> [((SignalValue, STM ()), [Event])]+eventGuards guards = [((Signal $ NoPoison n, actAlways acts), ab)+                     | (n, EventGuard _ acts ab) <- zip [0..] guards]+++-- Waits for one of the normal (non-alting barrier) guards to be ready,+-- or the given transaction to complete+waitNormalGuards :: [(Guard, b)] -> Maybe (STM b) -> IO (Bool, b)+waitNormalGuards guards extra+  = do enabled <- sequence $ mapMaybe enable guards+       atomically $ foldr orElse retry $ maybe id ((:) . liftM ((,) True)) extra $ enabled+  where+    enable :: (Guard, b) -> Maybe (IO (STM (Bool, b)))+    enable (SkipGuard, x) = Just $ return $ return (False, x)+    enable (TimeoutGuard g, x) = Just $ liftM (>> return (False, x)) g+    enable _ = Nothing -- This effectively ignores other guards+++++-- | An alt between several actions, with descending priority.  The first+-- available action is chosen (biased towards actions nearest the beginning+-- of the list), its body run, and its value returned.+--+-- What priority means here is a difficult thing, and in some ways a historical+-- artifact.  We can group the guards into three categories:+--+-- 1. synchronisation guards (reading from and writing to channels, and synchronising+-- on barriers)+--+-- 2. time-out guards (such as 'Control.Concurrent.CHP.Monad.waitFor')+--+-- 3. dummy guards ('Control.Concurrent.CHP.Monad.skip', 'Control.Concurrent.CHP.Monad.stop'+-- and things like IO actions)+--+-- There exists priority when comparing dummy guards to anything else.  So for+-- example,+--+-- > priAlt [ skip, x ]+--+-- Will always select the first guard (the skip guard), whereas:+--+-- > priAlt [ x , skip ]+--+-- Is an effective way to poll and see if x is ready, otherwise the 'Control.Concurrent.CHP.Monad.skip' will+-- be chosen.  However, there is no priority between synchronisation guards and+-- time-out guards.  So the two lines:+--+-- > priAlt [ x, y ]+-- > priAlt [ y, x ]+--+-- May have the same or different behaviour (when x and y are not dummy guards),+-- there is no guarantee either way.  The reason behind this is that if you ask+-- for:+--+-- > priAlt [ readChannel c, writeChannel d 6 ]+--+-- And the process at the other end is asking for:+--+-- > priAlt [ readChannel d, writeChannel c 8 ]+--+-- Whichever channel is chosen by both processes will not satisfy the priority+-- at one end (if such priority between channels was supported).  If you do want+-- priority that is globally consistent, look at the channel and barrier creation+-- methods for ways to set priority on events.+priAlt :: [CHP a] -> CHP a+priAlt xs = PoisonT $ \t f -> priAlt' t (map (wrapPoison t) xs) >>= f++priAlt' :: TraceStore -> [CHP' a] -> CHP' a+priAlt' tr = Altable tr . filter (not . isStopGuard . fst) . concatMap getAltable+  where+    getAltable :: CHP' a -> [(Guard, IO (WithPoison a))]+    getAltable (Return x) = [(SkipGuard, return $ NoPoison x)]+    getAltable (Altable _ gs) = gs+    getAltable (Standard m) = [(SkipGuard, m)]+++-- | The stop guard.  Its main use is that it is never ready in a choice, so+-- can be used to mask out guards.  If you actually execute 'stop', that process+-- will do nothing more.  Any parent process waiting for it to complete will+-- wait forever.+--+-- The type of this function was generalised in CHP 1.6.0.+stop :: CHP a+stop = makeAltable [(stopGuard, hang)]+  where+    -- Strangely, I can't work out a good way to actually implement stop.+    -- If you wait on a variable that will never be ready, GHC will wake+    -- you up with an exception.  If you loop doing that, you'll burn the+    -- CPU.  Throwing an exception would be caught and terminate the+    -- process, which is not the desired behaviour.  The only thing I can think+    -- to do is to repeatedly wait for a very long time.+    hang :: IO a+    hang = forever $ threadDelay maxBound
Control/Concurrent/CHP/CSP.hs view
@@ -32,38 +32,36 @@ -- TODO rename this module. module Control.Concurrent.CHP.CSP where +import Control.Applicative import Control.Concurrent.STM import Control.Exception-import Control.Monad.Reader+import Control.Monad (when) import Data.List import qualified Data.Map as Map import Data.Unique -import Control.Concurrent.CHP.Alt import Control.Concurrent.CHP.Base import qualified Control.Concurrent.CHP.Event as Event import Control.Concurrent.CHP.Enroll import Control.Concurrent.CHP.Guard+import Control.Concurrent.CHP.Poison import Control.Concurrent.CHP.Traces.Base  -- First engages in event, then executes the body.  The returned value is suitable -- for use in an alt-buildOnEventPoison :: (Unique -> (Unique -> (Integer, Event.RecordedEventType)) -> [RecordedIndivEvent Unique]) -> Event.Event -> EventActions -> CHP a -> CHP a+buildOnEventPoison :: (Unique -> (Unique -> (Integer, Event.RecordedEventType)) -> [RecordedIndivEvent Unique]) -> Event.Event -> EventActions -> IO (WithPoison a) -> CHP a buildOnEventPoison recE e act body-  = liftPoison (AltableT (Right [(theGuard, return True)])-                   (return False))-    >>= \b -> if b then body else-      alt [liftPoison $ AltableT (Right [(theGuard, return ())]) (return ())] >> body-    where-      theGuard = EventGuard (recE (Event.getEventUnique e)) act [e]+  = makeAltable [(theGuard, body)]+  where+    theGuard = EventGuard (recE (Event.getEventUnique e)) act [e]  scopeBlock :: CHP a -> (a -> CHP b) -> IO () -> CHP b scopeBlock start body errorEnd     = do x <- start-         tr <- liftPoison $ liftTrace ask-         y <- liftIO $ bracketOnError (return ()) (const errorEnd) $ const-           $ runReaderT (pullOutStandard (wrapPoison $ body x)) tr-         checkPoison y `onPoisonRethrow` (liftIO errorEnd)+         tr <- getTrace+         y <- liftIO_CHP $ bracketOnError (return ()) (const errorEnd) $ const+           $ pullOutStandard (wrapPoison tr $ body x)+         checkPoison y `onPoisonRethrow` (liftIO_CHP errorEnd)  wrapIndiv :: (Unique -> (Unique -> Integer) -> String -> [RecordedIndivEvent Unique])           -> Unique -> (Unique -> (Integer, Event.RecordedEventType))@@ -76,7 +74,7 @@   -> (Int -> STM ()) -> Enrolled PhasedBarrier phase -> CHP phase syncBarrierWith recE storeN (Enrolled (Barrier (e,tv, fph)))     = buildOnEventPoison (wrapIndiv recE) e (EventActions incPhase (return ()))-        (liftIO $ atomically $ readTVar tv)+        (NoPoison <$> (atomically $ readTVar tv))     where       incPhase :: Map.Map Unique Int -> STM ()       incPhase m = do readTVar tv >>= writeTVar tv . fph@@ -112,13 +110,13 @@     = do liftSTM (Event.enrollEvent e) >>= checkPoison          x <- f $ Enrolled b          liftSTM (Event.resignEvent e) >>= checkPoison >>= (\es ->-           do tr <- liftPoison $ liftTrace ask+           do tr <- getTrace               when (not $ null es) $ liftSTM $ recordEventLast (nub es) tr)          return x    resign (Enrolled (Barrier (e, _, _))) m     = do liftSTM (Event.resignEvent e) >>= checkPoison >>= (\es ->-           do tr <- liftPoison $ liftTrace ask+           do tr <- getTrace               when (not $ null es) $ liftSTM $ recordEventLast (nub es) tr)          x <- m          liftSTM (Event.enrollEvent e) >>= checkPoison@@ -126,7 +124,7 @@  instance Poisonable (Enrolled PhasedBarrier phase) where   poison (Enrolled (Barrier (e, _, _)))-    = liftSTM $ Event.poisonEvent e+    = liftCHP . liftSTM $ Event.poisonEvent e   checkForPoison (Enrolled (Barrier (e, _, _)))     = liftCHP $ liftSTM (Event.checkEventForPoison e) >>= checkPoison 
Control/Concurrent/CHP/Channels/Base.hs view
@@ -31,7 +31,6 @@  import Control.Concurrent.STM import Control.Monad-import Control.Monad.Trans import Data.Unique (Unique)  import Control.Concurrent.CHP.Base@@ -68,48 +67,17 @@   writer :: w a}  -class ChaninC c a where-  -- Start gets the event and the transaction that will wait for data.  You-  -- sync on the event (possible extended write occurs) then wait for data-  startReadChannelC :: c a -> (Event, STM (WithPoison a))-  -- (extended read action goes here)-  -- Read releases the writer-  endReadChannelC :: c a -> STM (WithPoison ())--  -- First action is to be done as part of the completion:-  readChannelC :: c a -> (Event, STM (), STM (WithPoison a))--  poisonReadC :: c a -> IO ()-  checkPoisonReadC :: c a -> IO (WithPoison ())--class ChanoutC c a where-  -- Start checks for poison and gets the event:-  startWriteChannelC :: c a -> (Event, STM (WithPoison ()))-  -- (extended write action goes here)-  -- Send actually transmits the value:-  sendWriteChannelC :: c a -> a -> STM (WithPoison ())-  -- (extended read action goes here)-  -- End waits for the reader to tell us we're done, must be done in a different-  -- transaction to the send-  endWriteChannelC :: c a -> STM (WithPoison ())--  -- First action is to be done as part of the completion:-  writeChannelC :: c a -> a -> (Event, STM (), STM (WithPoison ()))-  -  poisonWriteC :: c a -> IO ()-  checkPoisonWriteC :: c a -> IO (WithPoison ())- instance Poisonable (Chanin a) where-  poison (Chanin c) = liftIO $ poisonReadC c-  checkForPoison (Chanin c) = liftCHP $ liftIO (checkPoisonReadC c) >>= checkPoison+  poison (Chanin c) = liftCHP . liftIO_CHP $ poisonReadC c+  checkForPoison (Chanin c) = liftCHP $ liftIO_CHP (checkPoisonReadC c) >>= checkPoison  instance Poisonable (Chanout a) where-  poison (Chanout c) = liftIO $ poisonWriteC c-  checkForPoison (Chanout c) = liftCHP $ liftIO (checkPoisonWriteC c) >>= checkPoison+  poison (Chanout c) = liftCHP . liftIO_CHP $ poisonWriteC c+  checkForPoison (Chanout c) = liftCHP $ liftIO_CHP (checkPoisonWriteC c) >>= checkPoison  -stmChannel :: MonadIO m => Int -> (a -> String) -> m (Unique, STMChannel a)-stmChannel pri sh = liftIO $+stmChannel :: Int -> (a -> String) -> IO (Unique, STMChannel a)+stmChannel pri sh =   do c <- atomically $ newTVar $ NoPoison (Nothing, Nothing)      e <- newEventPri (liftM (ChannelComm . maybe "" sh . getVal) $ readTVar c) 2 pri      return (getEventUnique e, STMChan (e,c))@@ -128,11 +96,18 @@                       NoPoison (Just x, a) -> do writeTVar tv $ NoPoison (Nothing, a)                                                  return $ NoPoison x +sharedError :: String -> String+sharedError s+  = unlines ["CHP: Assumption violated; found " ++ s ++ " when placing " ++ s ++ "."+            ,"This is typically because you have multiple writers or multiple readers accessing a unshared (one-to-one) channel."+            ,"If you want to have many writers or many readers, use an appropriate (any-to-one, one-to-any or any-to-any) shared channel, using the claim function."+            ]+ sendData :: TVar (WithPoison (Maybe a, Maybe ())) -> a -> STM (WithPoison ()) sendData tv x  = do y <- readTVar tv                     case y of                       PoisonItem -> return PoisonItem-                      NoPoison (Just _, _) -> error "CHP: Found data while sending data"+                      NoPoison (Just _, _) -> error $ sharedError "data"                       NoPoison (Nothing, a) -> do writeTVar tv $ NoPoison (Just x, a)                                                   return $ NoPoison () @@ -148,35 +123,62 @@ sendAck tv =    do d <- readTVar tv                    case d of                       PoisonItem -> return PoisonItem-                      NoPoison (_, Just _) -> error "CHP: Found ack while placing ack!"+                      NoPoison (_, Just _) -> error $ sharedError "ack"                       NoPoison (x, Nothing) -> do writeTVar tv $ NoPoison (x, Just ())                                                   return $ NoPoison () -instance ChaninC STMChannel a where-  startReadChannelC (STMChan (e,tv)) = (e, consumeData tv)-  endReadChannelC (STMChan (_,tv)) = sendAck tv-  readChannelC (STMChan (e, tv))-    = (e, sendAck tv >> return (), consumeData tv)+-- Start gets the event and the transaction that will wait for data.  You+-- sync on the event (possible extended write occurs) then wait for data+startReadChannelC :: STMChannel a -> (Event, STM (WithPoison a))+startReadChannelC (STMChan (e,tv)) = (e, consumeData tv) -  poisonReadC (STMChan (e,tv))-    = liftSTM $ do poisonEvent e-                   writeTVar tv PoisonItem-  checkPoisonReadC (STMChan (e,_)) = liftSTM $ checkEventForPoison e+-- (extended read action goes here)+-- Read releases the writer+endReadChannelC :: STMChannel a -> STM (WithPoison ())+endReadChannelC (STMChan (_,tv)) = sendAck tv -instance ChanoutC STMChannel a where-  startWriteChannelC (STMChan (e,tv))+-- First action is to be done as part of the completion:+readChannelC :: STMChannel a -> (Event, STM (), STM (WithPoison a))+readChannelC (STMChan (e, tv))+  = (e, sendAck tv >> return (), consumeData tv)++poisonReadC :: STMChannel a -> IO ()+poisonReadC (STMChan (e,tv))+    = atomically $ do poisonEvent e+                      writeTVar tv PoisonItem++checkPoisonReadC :: STMChannel a -> IO (WithPoison ())+checkPoisonReadC (STMChan (e,_)) = atomically $ checkEventForPoison e++-- Start checks for poison and gets the event:+startWriteChannelC :: STMChannel a -> (Event, STM (WithPoison ()))+startWriteChannelC (STMChan (e,tv))     = (e, do x <- readTVar tv              case x of                PoisonItem -> return PoisonItem                NoPoison _ -> return $ NoPoison ())-  sendWriteChannelC (STMChan (_, tv)) = sendData tv-  endWriteChannelC (STMChan (_, tv))++-- (extended write action goes here)+-- Send actually transmits the value:+sendWriteChannelC :: STMChannel a -> a -> STM (WithPoison ())+sendWriteChannelC (STMChan (_, tv)) = sendData tv++-- (extended read action goes here)+-- End waits for the reader to tell us we're done, must be done in a different+-- transaction to the send+endWriteChannelC :: STMChannel a -> STM (WithPoison ())+endWriteChannelC (STMChan (_, tv))     = consumeAck tv -  writeChannelC (STMChan (e, tv)) val+-- First action is to be done as part of the completion:+writeChannelC :: STMChannel a -> a -> (Event, STM (), STM (WithPoison ()))+writeChannelC (STMChan (e, tv)) val     = (e, sendData tv val >> return (), consumeAck tv) -  poisonWriteC (STMChan (e,tv))-    = liftSTM $ do poisonEvent e-                   writeTVar tv PoisonItem-  checkPoisonWriteC (STMChan (e,_)) = liftSTM $ checkEventForPoison e+poisonWriteC :: STMChannel a -> IO ()+poisonWriteC (STMChan (e,tv))+  = atomically $ do poisonEvent e+                    writeTVar tv PoisonItem++checkPoisonWriteC :: STMChannel a -> IO (WithPoison ())+checkPoisonWriteC (STMChan (e,_)) = atomically $ checkEventForPoison e
Control/Concurrent/CHP/Channels/BroadcastReduce.hs view
@@ -74,7 +74,6 @@ import Control.Arrow import Control.Concurrent.STM import Control.Monad-import Control.Monad.Trans import Data.Monoid  import Control.Concurrent.CHP.Barriers@@ -117,18 +116,18 @@            (resetManyToOneTVar tvAck . pred) $ Enrolled b            -- subtract one for writer          (x, r) <- m-         liftIO . atomically $ writeTVar tvSend $ Just x+         liftSTM $ writeTVar tvSend $ Just x          -- Must be two separate transactions:-         _ <- liftIO . atomically $ readManyToOneTVar tvAck+         _ <- liftSTM $ readManyToOneTVar tvAck          return r  instance ReadableChannel (Enrolled BroadcastChanin) where   extReadChannel (Enrolled (BI (BC (b, tvSend, tvAck)))) f     = do syncBarrierWith (indivRecJust ChannelRead)            (resetManyToOneTVar tvAck . pred) $ Enrolled b-         x <- liftIO $ atomically $ readTVar tvSend >>= maybe retry return+         x <- liftSTM $ readTVar tvSend >>= maybe retry return          y <- f x-         _ <- liftIO $ atomically $ writeManyToOneTVar pred tvAck+         _ <- liftSTM $ writeManyToOneTVar pred tvAck          return y  instance Poisonable (BroadcastChanout a) where@@ -143,9 +142,9 @@ newBroadcastChannel   = do b@(Barrier (e, _, _)) <- newBarrier        -- Writer is always enrolled:-       _ <- liftIO $ atomically $ enrollEvent e-       tvSend <- liftIO $ atomically $ newTVar Nothing-       tvAck <- liftIO $ atomically $ newManyToOneTVar (== 0) (return 0) 0+       _ <- liftSTM $ enrollEvent e+       tvSend <- liftSTM $ newTVar Nothing+       tvAck <- liftSTM $ newManyToOneTVar (== 0) (return 0) 0        return $ BC (b, tvSend, tvAck)  instance Channel BroadcastChanin BroadcastChanout where@@ -156,7 +155,7 @@  instance Channel BroadcastChanin (Shared BroadcastChanout) where   newChannel' _sh = liftCHP $ do-    m <- newMutex+    m <- liftIO_CHP newMutex     c <- newChannel     return $ Chan (getChannelIdentifier c) (reader c) (Shared (m, writer c))   sameChannel (BI x) (Shared (_, BO y)) = x == y@@ -215,12 +214,12 @@            (\n -> resetManyToOneTVar tv (pred n, Nothing)) $ Enrolled b            -- Subtract one for reader          (x, r) <- m-         (_, Just (_, rtvb)) <- liftIO . atomically $ do+         (_, Just (_, rtvb)) <- liftSTM $ do            tvb <- newTVar False            let upd (n, mx) = (pred n, Just $ maybe (x, tvb) (first $ f x) mx)            writeManyToOneTVar upd tv          -- Has to be two separate transactions-         liftIO $ atomically $ readTVar rtvb >>= flip unless retry+         liftSTM $ readTVar rtvb >>= flip unless retry          return r  instance ReadableChannel ReduceChanin where@@ -228,10 +227,10 @@     = do syncBarrierWith (indivRecJust ChannelRead)            (\n -> resetManyToOneTVar tv (pred n, Nothing)) $ Enrolled b            -- Subtract one for reader-         (_, val) <- liftIO $ atomically $ readManyToOneTVar tv+         (_, val) <- liftSTM $ readManyToOneTVar tv          case val of            Just (x, tvb) -> do y <- f x-                               liftIO $ atomically $ writeTVar tvb True+                               liftSTM $ writeTVar tvb True                                return y            Nothing -> f empty @@ -247,8 +246,8 @@ newReduceChannel   = do b@(Barrier (e, _, _)) <- newBarrier        -- Writer is always enrolled:-       _ <- liftIO $ atomically $ enrollEvent e-       mtv <- liftIO $ atomically $ newManyToOneTVar ((== 0) . fst) (return (0, Nothing)) (0, Nothing)+       _ <- liftSTM $ enrollEvent e+       mtv <- liftSTM $ newManyToOneTVar ((== 0) . fst) (return (0, Nothing)) (0, Nothing)        return $ GC (b, mtv, (mappend, mempty))  -- | The reduce channel version of sameChannel.@@ -268,7 +267,7 @@  manyToAnyChannel :: (Monoid a, MonadCHP m) => m (ManyToAnyChannel a) manyToAnyChannel = do-    m <- newMutex+    m <- liftCHP $ liftIO_CHP newMutex     c <- manyToOneChannel     return $ Chan (getChannelIdentifier c) (Shared (m, reader c)) (writer c) 
Control/Concurrent/CHP/Channels/Communication.hs view
@@ -56,7 +56,7 @@   ReadableChannel(..), WriteableChannel(..), writeValue, writeChannelStrict   ) where -+import Control.Concurrent.STM (atomically) import Control.DeepSeq import Control.Monad import Data.Monoid@@ -132,12 +132,12 @@     = let (e, mdur, mafter) = readChannelC c in       buildOnEventPoison (wrapIndiv $ indivRecJust ChannelRead) e         (EventActions (const $ return ()) mdur)-        (liftSTM mafter) >>= checkPoison+        (atomically mafter)    extReadChannel (Chanin c) body     = let (e, m) = startReadChannelC c in       scopeBlock-        (buildOnEventPoison (wrapIndiv $ indivRecJust ChannelRead) e mempty (liftSTM m) >>= checkPoison)+        (buildOnEventPoison (wrapIndiv $ indivRecJust ChannelRead) e mempty (atomically m))         (\val -> do x <- body val                     _ <- liftSTM $ endReadChannelC c                     return x)@@ -147,13 +147,12 @@   writeChannel (Chanout c) x     = let (e, mdur, mafter) = writeChannelC c x in         buildOnEventPoison (wrapIndiv $ indivRecJust ChannelWrite) e-          (EventActions (const $ return ()) mdur) (liftSTM mafter)-        >>= checkPoison+          (EventActions (const $ return ()) mdur) (atomically mafter)   extWriteChannel' (Chanout c) body     = let (e, m) = startWriteChannelC c in       scopeBlock         (buildOnEventPoison (wrapIndiv $ indivRecJust ChannelWrite)-          e mempty (liftSTM m) >>= checkPoison)+          e mempty (atomically m))         (const $ do (x, r) <- body                     sequence [liftSTM $ sendWriteChannelC c x                              ,liftSTM (endWriteChannelC c)]
Control/Concurrent/CHP/Channels/Creation.hs view
@@ -63,7 +63,7 @@ -- the channels in traces).  Instead of using @oneToOneChannelWithLabel "foo"@, -- you should use @oneToOneChannel' $ chanLabel "foo"@. module Control.Concurrent.CHP.Channels.Creation (-  Chan, Channel(..), newChannel, ChanOpts(..), defaultChanOpts, chanLabel, newChannelWR, newChannelRW, ChannelTuple(..),+  Chan, Channel(..), newChannel, ChanOpts(..), defaultChanOpts, chanLabel, newChannelWR, newChannelRW,   newChannelList, newChannelListWithLabels, newChannelListWithStem,   labelChannel   ) where@@ -137,17 +137,6 @@ newChannel :: (MonadCHP m, Channel r w) => m (Chan r w a) newChannel = newChannel' defaultChanOpts --- | A helper class for easily creating several channels of the same type.---  The same type refers not only to what type the channel carries, but---  also to the type of channel (one-to-one no poison, one-to-any with---  poison, etc).  You can write code like this:------ > (a, b, c, d, e) <- newChannels------ To create five channels of the same type.-class ChannelTuple t where-  newChannels :: MonadCHP m => m t- -- | A helper that is like 'newChannel' but returns the reading and writing -- end of the channels directly. newChannelRW :: (Channel r w, MonadCHP m) => m (r a, w a)@@ -178,76 +167,38 @@ newChannelListWithLabels :: (Channel r w, MonadCHP m) => [String] -> m [Chan r w a] newChannelListWithLabels = mapM (newChannel' . ChanOpts 0 (const "") . Just) -instance (Channel r w) => ChannelTuple (Chan r w a, Chan r w a) where-  newChannels = do c0 <- newChannel-                   c1 <- newChannel-                   return (c0, c1)--instance (Channel r w) => ChannelTuple (Chan r w a, Chan r w a, Chan r w a) where-  newChannels = do c0 <- newChannel-                   c1 <- newChannel-                   c2 <- newChannel-                   return (c0, c1, c2)--instance (Channel r w) => ChannelTuple (Chan r w a, Chan r w a, Chan r w a,-  Chan r w a) where-  newChannels = do c0 <- newChannel-                   c1 <- newChannel-                   c2 <- newChannel-                   c3 <- newChannel-                   return (c0, c1, c2, c3)--instance (Channel r w) => ChannelTuple (Chan r w a, Chan r w a, Chan r w a,-  Chan r w a, Chan r w a) where-  newChannels = do c0 <- newChannel-                   c1 <- newChannel-                   c2 <- newChannel-                   c3 <- newChannel-                   c4 <- newChannel-                   return (c0, c1, c2, c3, c4)--instance (Channel r w) => ChannelTuple (Chan r w a, Chan r w a, Chan r w a,-  Chan r w a, Chan r w a, Chan r w a) where-  newChannels = do c0 <- newChannel-                   c1 <- newChannel-                   c2 <- newChannel-                   c3 <- newChannel-                   c4 <- newChannel-                   c5 <- newChannel-                   return (c0, c1, c2, c3, c4, c5)- -- | Labels a channel in the traces.  It is easiest to do this at creation. -- The effect of re-labelling channels after their first use is undefined. -- -- Added in version 1.5.0. labelChannel :: MonadCHP m => Chan r w a -> String -> m ()-labelChannel c = liftCHP . liftPoison . liftTrace . labelUnique (getChannelIdentifier c)+labelChannel c s = liftCHP $ getTrace >>= \t -> liftIO_CHP $ labelUnique t (getChannelIdentifier c) s   instance Channel Chanin Chanout where-  newChannel' o = do c <- chan (stmChannel (chanOptsPriority o) (chanOptsShow o)) Chanin Chanout+  newChannel' o = do c <- chan (liftCHP . liftIO_CHP $ stmChannel (chanOptsPriority o) (chanOptsShow o)) Chanin Chanout                      maybe (return ()) (labelChannel c) (chanOptsLabel o)                      return c   sameChannel (Chanin x) (Chanout y) = x == y  instance Channel (Shared Chanin) Chanout where   newChannel' o = do-                  m <- newMutex+                  m <- liftCHP . liftIO_CHP $ newMutex                   c <- newChannel' o                   return $ Chan (getChannelIdentifier c) (Shared (m, reader c)) (writer c)   sameChannel (Shared (_, Chanin x)) (Chanout y) = x == y  instance Channel Chanin (Shared Chanout) where   newChannel' o = do-                  m <- newMutex+                  m <- liftCHP . liftIO_CHP $ newMutex                   c <- newChannel' o                   return $ Chan (getChannelIdentifier c) (reader c) (Shared (m, writer c))   sameChannel (Chanin x) (Shared (_, Chanout y)) = x == y  instance Channel (Shared Chanin) (Shared Chanout) where   newChannel' o = do-                  m <- newMutex-                  m' <- newMutex+                  m <- liftCHP . liftIO_CHP $ newMutex+                  m' <- liftCHP . liftIO_CHP $ newMutex                   c <- newChannel' o                   return $ Chan (getChannelIdentifier c) (Shared (m, reader c)) (Shared (m', writer c))   sameChannel (Shared (_, Chanin x)) (Shared (_, Chanout y)) = x == y
Control/Concurrent/CHP/Channels/Ends.hs view
@@ -38,8 +38,6 @@   reader, writer, readers, writers,   claim) where -import Control.Monad.Trans (liftIO)- import Control.Concurrent.CHP.Base import Control.Concurrent.CHP.CSP import Control.Concurrent.CHP.Channels.Base@@ -62,8 +60,8 @@ claim :: Shared c a -> (c a -> CHP b) -> CHP b claim (Shared (lock, c)) body   = scopeBlock-       (claimMutex lock >> return c)+       (liftIO_CHP (claimMutex lock) >> return c)        (\y -> do x <- body y-                 liftIO $ releaseMutex lock+                 liftIO_CHP $ releaseMutex lock                  return x)        (releaseMutex lock)
Control/Concurrent/CHP/Clocks.hs view
@@ -120,8 +120,6 @@  import Control.Concurrent.STM import Control.Monad hiding (mapM, mapM_)-import Control.Monad.Reader (ask)-import Control.Monad.Trans import Data.Foldable (mapM_) -- Needed for testing: --import Data.Maybe@@ -327,14 +325,14 @@          liftSTM (modifyTVar tv $ enrollTimerData $ Just ev)            >>= checkPoison          x <- f $ Enrolled tim-         ts <- liftPoison . liftTrace $ ask+         ts <- getTrace          liftSTM (modifyTVar' tv $ checkCompletion u sh ts . resignTimerData True)            >>= checkPoison          return x    -- For temporary resignations, we don't touch the event pool   resign (Enrolled (Clock (tv, u, sh))) m-    = do ts <- liftPoison . liftTrace $ ask+    = do ts <- getTrace          liftSTM (modifyTVar' tv (checkCompletion u sh ts . resignTimerData False))            >>= checkPoison          x <- m@@ -406,32 +404,34 @@ -- to display times in traces. newClock :: (Ord time, Show time) => time -> CHP (Clock time) newClock t = do tv <- liftSTM $ newTVar $ NoPoison $ emptyTimerData t-                u <- liftIO Event.newEventUnique+                u <- liftIO_CHP Event.newEventUnique                 return $ Clock (tv, u, show)  -- | Creates a clock that starts at the given time, and gives it the given -- label in traces.  The Show instance is needed to display times in traces. newClockWithLabel :: (Ord time, Show time) =>   time -> String -> CHP (Clock time)-newClockWithLabel t l = do tv <- liftSTM $ newTVar $ NoPoison $ emptyTimerData t-                           u <- liftIO Event.newEventUnique-                           liftPoison $ liftTrace $ labelUnique u l+newClockWithLabel t l = getTrace >>= \tr -> liftIO_CHP $+                        do tv <- atomically $ newTVar $ NoPoison $ emptyTimerData t+                           u <- Event.newEventUnique+                           labelUnique tr u l                            return $ Clock (tv, u, show)  instance Waitable Clock where   getCurrentTime (Enrolled (Clock (tv, _, _)))     = liftSTM (liftM (fmap curTime) $ readTVar tv) >>= checkPoison   wait c@(Enrolled (Clock (_, u, sh))) mt-    = do ts <- liftPoison . liftTrace $ ask-         pid <- liftPoison . liftTrace $ getProcessId-         waitAct <- liftSTM $ waitClock pid ts c mt+    = do tr <- getTrace+         let pid = getProcessId tr+         waitAct <- liftSTM $ waitClock pid tr c mt          (t, s) <- liftSTM waitAct >>= checkPoison-         liftPoison $ liftTrace $ recordEvent [ClockSyncIndiv u s $ sh t]+         liftIO_CHP $ recordEvent [ClockSyncIndiv u s $ sh t] tr          return t  instance Ord time => Poisonable (Enrolled Clock time) where   poison (Enrolled (Clock (tv,_,_)))-    = liftSTM $ do x <- readTVar tv+    = liftCHP . liftSTM $ do+                   x <- readTVar tv                    case x of                      PoisonItem -> return ()                      NoPoison td -> do poisonTimerData td
Control/Concurrent/CHP/Event.hs view
@@ -44,7 +44,6 @@ import Control.Concurrent.STM hiding (always) import Control.Concurrent.CHP.EventType import Control.Monad-import Control.Monad.Reader #ifdef CHP_TEST import Control.Monad.State #endif@@ -92,7 +91,7 @@ -- Nothing if resigning checkEvent :: CurOfferSet -> SearchState -> Event -> DiscoverM SearchState checkEvent cos ss e = do-  s <- lift $ readTVar $ getEventTVar e+  s <- liftWPMT $ readTVar $ getEventTVar e   case s of     PoisonItem -> WPMT $ return PoisonItem     NoPoison (enrollCount, _, offers) ->@@ -218,8 +217,10 @@ instance Monad m => Functor (WithPoisonMaybeT m) where   fmap f = WPMT . liftM (fmap (fmap f)) . runWPMT -instance MonadTrans WithPoisonMaybeT where-  lift = WPMT . liftM (NoPoison . Just)+liftWPMT :: Monad m => m a -> WithPoisonMaybeT m a+liftWPMT = WPMT . liftM (NoPoison . Just)++  instance (Monad m) => Applicative (WithPoisonMaybeT m) where   pure = return
Control/Concurrent/CHP/Guard.hs view
@@ -31,7 +31,6 @@  import Control.Concurrent.STM import Control.Monad-import Control.Monad.Trans import qualified Data.Map as Map import Data.Monoid import Data.Unique@@ -76,7 +75,7 @@ guardWaitFor :: Int -> Guard guardWaitFor n   = TimeoutGuard $ -     do signalDone <- liftIO $ registerDelay n+     do signalDone <- registerDelay n         return $ do b <- readTVar signalDone                     when (not b) retry 
Control/Concurrent/CHP/Monad.hs view
@@ -31,17 +31,19 @@ module Control.Concurrent.CHP.Monad   (    -- * CHP Monad-  CHP, MonadCHP(..), runCHP, runCHP_,+  CHP, MonadCHP(..), liftIO_CHP, runCHP, runCHP_,   embedCHP, embedCHP_, embedCHP1, embedCHP1_,    onPoisonTrap, onPoisonRethrow, throwPoison, Poisonable(..), poisonAll,    -- * Primitive actions-  skip, stop, waitFor+  skip, stop, waitFor,++  -- * chp-spec items+  foreverP, liftIO_CHP', process, subProcess    ) where -import Control.Concurrent-import Control.Monad.Reader+import Control.Monad (liftM, forever) import Data.Unique  -- This module primarily re-exports the public definitions from@@ -49,6 +51,7 @@  import Control.Concurrent.CHP.Base import Control.Concurrent.CHP.Guard+import Control.Concurrent.CHP.Poison import Control.Concurrent.CHP.Traces.TraceOff  -- | Runs a CHP program.  You should use this once, at the top-level of your@@ -62,6 +65,27 @@ runCHP_ :: CHP a -> IO () runCHP_ p = runCHP p >> return () +-- | Exactly the same as 'forever'.  Useful only because it mirrors a different definition+-- from the chp-spec library.+--+-- Added in version 2.2.0.+foreverP :: CHP a -> CHP b+foreverP = forever++-- | Acts as @const id@.  Useful only because it mirrors a different definition in the+-- chp-spec library.+--+-- Added in version 2.2.0.+process :: String -> a -> a+process = const id++-- | Acts as @const id@.  Useful only because it mirrors a different definition in the+-- chp-spec library.+--+-- Added in version 2.2.0.+subProcess :: String -> a -> a+subProcess = const id+ -- | Allows embedding of the CHP monad back into the IO monad.  The argument -- that this function takes is a CHP action (with arbitrary behaviour).  The -- function is monadic, and returns something of type: IO a.  This@@ -81,7 +105,7 @@  -- | A helper like embedCHP for callbacks that take an argument embedCHP1 :: (a -> CHP b) -> CHP (a -> IO (Maybe b))-embedCHP1 f = do t <- liftPoison $ liftTrace ask+embedCHP1 f = do t <- getTrace                  return $ runCHPProgramWith t . f  -- | A convenient version of embedCHP1 that ignores the result@@ -102,7 +126,7 @@ -- /NOTE:/ If you wish to use this as part of a choice, you must use @-threaded@ -- as a GHC compilation option (at least under 6.8.2). waitFor :: Int -> CHP ()-waitFor n = liftPoison $ AltableT (Right [(guardWaitFor n, return ())]) (liftIO $ threadDelay n)+waitFor n = makeAltable [(guardWaitFor n, return $ NoPoison ())] -- TODO maybe fix the above lack of guarantees by keeping timeout guards explicit.  -- TODO add waitUntil@@ -111,23 +135,11 @@ -- -- Suitable for use in an 'Control.Concurrent.CHP.Alt.alt'. skip :: CHP ()-skip = liftPoison $ AltableT (Right [(skipGuard, return ())]) (return ())+skip = makeAltable [(skipGuard, return $ NoPoison ())] --- | The stop guard.  Its main use is that it is never ready in a choice, so--- can be used to mask out guards.  If you actually execute 'stop', that process--- will do nothing more.  Any parent process waiting for it to complete will--- wait forever.+-- | Acts as @const liftIO_CHP@.  Useful only because it mirrors a different definition in the+-- chp-spec library. ----- The type of this function was generalised in CHP 1.6.0.-stop :: CHP a-stop = liftPoison $ AltableT (Right [(stopGuard, liftIO hang)]) (liftIO hang)-  where-    -- Strangely, I can't work out a good way to actually implement stop.-    -- If you wait on a variable that will never be ready, GHC will wake-    -- you up with an exception.  If you loop doing that, you'll burn the-    -- CPU.  Throwing an exception would be caught and terminate the-    -- process, which is not the desired behaviour.  The only thing I can think-    -- to do is to repeatedly wait for a very long time.-    hang :: IO a-    hang = forever $ threadDelay maxBound-+-- Added in version 2.2.0.+liftIO_CHP' :: String -> IO a -> CHP a+liftIO_CHP' = const liftIO_CHP
Control/Concurrent/CHP/Mutex.hs view
@@ -30,18 +30,17 @@ module Control.Concurrent.CHP.Mutex where  import Control.Concurrent-import Control.Monad.Trans  type Mutex = MVar () -claimMutex :: MonadIO m => Mutex -> m ()-claimMutex = liftIO . takeMVar+claimMutex :: Mutex -> IO ()+claimMutex = takeMVar -newMutex :: MonadIO m => m Mutex-newMutex = liftIO $ newMVar ()+newMutex :: IO Mutex+newMutex = newMVar () -releaseMutex :: MonadIO m => Mutex -> m ()-releaseMutex m = liftIO $ putMVar m ()+releaseMutex :: Mutex -> IO ()+releaseMutex m = putMVar m ()  -- | A wrapper (usually around a channel-end) indicating that the inner item -- is shared.  Use the 'claim' function to use this type.
Control/Concurrent/CHP/Parallel.hs view
@@ -28,17 +28,18 @@ -- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  module Control.Concurrent.CHP.Parallel (runParallel, runParallel_, (<||>), (<|*|>),-  runParMapM, runParMapM_, ForkingT, forking, fork) where+  runParMapM, runParMapM_ , ForkingT, liftForking, forking, fork) where  import Control.Concurrent import Control.Concurrent.STM+import Control.Monad (liftM) import qualified Control.Exception.Extensible as C-import Control.Monad.Reader import Data.List import Data.Maybe import Data.Ord  import Control.Concurrent.CHP.Base+import Control.Concurrent.CHP.Poison import Control.Concurrent.CHP.Traces.Base  -- | This type-class supports parallel composition of processes.  You may use@@ -114,35 +115,46 @@ -- | Runs all the processes in parallel and returns their results once they -- have all finished.  The length and ordering of the results reflects the -- length and ordering of the input-runParallelPoison :: forall a. [CHP a] -> CHP [a]+runParallelPoison :: [CHP a] -> CHP [a] runParallelPoison processes-  = do resultVar <- liftIO $ atomically $ newManyToOneTVar+  = do resultVar <- liftIO_CHP $ atomically $ newManyToOneTVar          ((== length processes) . length) (return []) []-       trace <- PoisonT $ lift $ liftTrace ask-       blanks <- liftIO $ blankTraces trace (length processes)-       liftIO $ -         mapM_ forkIO [do y <- wrapProcess p $ flip runReaderT btr . pullOutStandard+       trace <- getTrace+       blanks <- liftIO_CHP $ blankTraces trace (length processes)+       liftIO_CHP $ +         mapM_ forkIO [do y <- wrapProcess p btr pullOutStandard                           C.block $ atomically $                             writeManyToOneTVar                              ((:) (case y of                                  Nothing -> (n, Nothing)-                                 Just (Right x) -> (n, Just x)-                                 Just (Left _) -> (n, Nothing)+                                 Just (NoPoison x) -> (n, Just x)+                                 Just PoisonItem -> (n, Nothing)                                  )) resultVar                              >> return ()                       | (p, btr, n) <- zip3 processes blanks [(0::Int)..]]-       results <- liftIO $ atomically $ readManyToOneTVar resultVar+       results <- liftIO_CHP $ atomically $ readManyToOneTVar resultVar        let sortedResults = map snd $ sortBy (comparing fst) results-       PoisonT $ lift $ liftTrace $ mergeSubProcessTraces blanks+       liftIO_CHP $ mergeSubProcessTraces blanks trace        mapM (maybe throwPoison return) sortedResults  -- | A monad transformer used for introducing forking blocks.-newtype (Monad m, MonadCHP m) => ForkingT m a = Forking (ReaderT (TVar (Bool,-  Int)) m a)-  deriving (Monad, MonadIO, MonadTrans, MonadCHP)+newtype ForkingT m a = Forking {runForkingT :: TVar (Bool, Int) -> m a } +instance Monad m => Monad (ForkingT m) where+  return = liftForking . return+  m >>= k = Forking $ \tv -> runForkingT m tv >>= (flip runForkingT tv . k)++instance MonadCHP m => MonadCHP (ForkingT m) where+  liftCHP = liftForking . liftCHP+ -- TODO in future, get forking working with structural traces +-- | An implementation of lift for the ForkingT monad transformer.+--+-- Added in version 2.2.0.+liftForking :: Monad m => m a -> ForkingT m a+liftForking = Forking . const+ -- | Executes a forking block.  Processes may be forked off inside (using the -- 'fork' function).  When the block completes, it waits for all the forked -- off processes to complete before returning the output, as long as none of@@ -150,9 +162,9 @@ -- is propagated (rethrown). forking :: MonadCHP m => ForkingT m a -> m a -- Like with parallel, this could probably be made a little more efficient-forking (Forking m) = do b <- liftIO $ atomically $ newTVar (False, 0)-                         output <- runReaderT m b-                         p <- liftIO $ atomically $ do+forking (Forking m) = do b <- liftCHP . liftSTM $ newTVar (False, 0)+                         output <- m b+                         p <- liftCHP . liftSTM $ do                            (p,n) <- readTVar b                            if n == 0                              then return p@@ -167,15 +179,14 @@ -- are waited for.  At that point, once all of the processes have finished, -- if any of them threw poison it is propagated. fork :: MonadCHP m => CHP () -> ForkingT m ()-fork p = Forking $-           do b <- ask-              liftIO $ atomically $ do+fork p = Forking $ \b ->+           do liftCHP . liftSTM $ do                 (pa, n) <- readTVar b                 writeTVar b (pa, n + 1)-              trace <- liftCHP $ PoisonT $ lift $ liftTrace ask-              [blank] <- liftIO $ blankTraces trace 1-              _ <- liftIO $ forkIO $ do-                r <- wrapProcess p $ flip runReaderT blank . pullOutStandard+              trace <- liftCHP getTrace+              [blank] <- liftCHP . liftIO_CHP $ blankTraces trace 1+              _ <- liftCHP . liftIO_CHP $ forkIO $ do+                r <- wrapProcess p blank pullOutStandard                 C.block $ atomically $ do                   (poisonedAlready, n) <- readTVar b                   writeTVar b (poisonedAlready || isNothing r, n - 1)
Control/Concurrent/CHP/Traces/Base.hs view
@@ -30,8 +30,7 @@ module Control.Concurrent.CHP.Traces.Base where  import Control.Concurrent.STM-import Control.Monad.Reader-import Control.Monad.State+import Control.Monad (liftM) import Data.IORef import Data.List import qualified Data.Map as Map@@ -102,16 +101,22 @@  type RecEvents = ([RecordedEvent Unique], [RecordedIndivEvent Unique]) -getName :: Ord u => String -> u -> State (Map.Map u String) String-getName prefix u-          = do m <- get+data LabelM u a = LabelM { runLabelM :: ChannelLabels u -> (a, ChannelLabels u) }++labelWith :: LabelM u a -> ChannelLabels u -> a+labelWith = (fst .) . runLabelM++instance Monad (LabelM u) where+  return = LabelM . (,)+  m >>= k = LabelM $ \s -> let (a, s') = runLabelM m s in runLabelM (k a) s'++getName :: Ord u => String -> u -> LabelM u String+getName prefix u = LabelM $ \m ->                case Map.lookup u m of-                 Just x -> return x-                 Nothing -> let x = prefix ++ show (Map.size m) in-                            do put $ Map.insert u x m-                               return x+                 Just x -> (x, m)+                 Nothing -> let x = prefix ++ show (Map.size m) in (x, Map.insert u x m) -nameEvent :: Ord u => RecordedEvent u -> State (Map.Map u String) String+nameEvent :: Ord u => RecordedEvent u -> LabelM u String nameEvent (t, c) = liftM (++ suffix) $ getName prefix c   where     (prefix, suffix) = case t of@@ -119,7 +124,7 @@       BarrierSync x -> ("_b", if null x then "" else '.' : x)       ClockSync st -> ("_t", ':' : st) -nameEvent' :: Ord u => RecordedEvent u -> State (Map.Map u String) (RecordedEvent String)+nameEvent' :: Ord u => RecordedEvent u -> LabelM u (RecordedEvent String) nameEvent' (t, c) = do c' <- getName prefix c                        return (t, c' ++ suffix)   where@@ -129,7 +134,7 @@       ClockSync st -> ("_t", ':' : st)  -nameIndivEvent :: Ord u => RecordedIndivEvent u -> State (Map.Map u String) String+nameIndivEvent :: Ord u => RecordedIndivEvent u -> LabelM u String nameIndivEvent (ChannelWrite c n _) = do c' <- getName "_c" c                                          return $ c' ++ "![" ++ show n ++ "]" nameIndivEvent (ChannelRead c n _) = do c' <- getName "_c" c@@ -140,7 +145,7 @@                                            return $ c' ++ ":" ++ t                                              ++ "[" ++ show n ++ "]" -nameIndivEvent' :: Ord u => RecordedIndivEvent u -> State (Map.Map u String) (RecordedIndivEvent String)+nameIndivEvent' :: Ord u => RecordedIndivEvent u -> LabelM u (RecordedIndivEvent String) nameIndivEvent' (ChannelWrite c n x) = do c' <- getName "_c" c                                           return $ ChannelWrite c' n x nameIndivEvent' (ChannelRead c n x) = do c' <- getName "_c" c@@ -151,8 +156,6 @@                                             return $ ClockSyncIndiv c' n t  -type TraceT = ReaderT TraceStore- data TraceStore =   NoTrace ProcessId   | Trace (ProcessId, TVar (ChannelLabels Unique), SubTraceStore)@@ -204,15 +207,15 @@                  -> foldl (flip Set.insert) z news' : zs  -- | Records an event where you were one of the people involved-recordEvent :: [RecordedIndivEvent Unique] -> TraceT IO ()-recordEvent e = ask >>= lift . mapSubTrace recH+recordEvent :: [RecordedIndivEvent Unique] -> TraceStore -> IO ()+recordEvent e = mapSubTrace recH   where     recH (Hierarchy es) = modifyIORef es (addParEventsH (map StrEvent e))     recH _ = return () -mergeSubProcessTraces :: [TraceStore] -> TraceT IO ()+mergeSubProcessTraces :: [TraceStore] -> TraceStore -> IO () mergeSubProcessTraces ts-  = ask >>= lift . mapSubTrace merge+  = mapSubTrace merge   where     ts' = mapM readIORef [t | Trace (_,_,Hierarchy t) <- ts]     merge (Hierarchy es) = ts' >>= modifyIORef es . addParEventsH@@ -277,18 +280,17 @@ addRLE x nes = (1,[x]):nes  -labelEvent :: Event -> String -> TraceT IO ()-labelEvent e = labelUnique (getEventUnique e)+labelEvent :: TraceStore -> Event -> String -> IO ()+labelEvent t e = labelUnique t (getEventUnique e) -labelUnique :: Unique -> String -> TraceT IO ()-labelUnique u l-  = do t <- ask-       case t of-         NoTrace {} -> return ()-         Trace (_,tvls,_) -> add tvls+labelUnique :: TraceStore -> Unique -> String -> IO ()+labelUnique t u l+  = case t of+       NoTrace {} -> return ()+       Trace (_,tvls,_) -> add tvls   where-    add :: TVar (Map.Map Unique String) -> TraceT IO ()-    add tv = liftIO $ atomically $ do+    add :: TVar (Map.Map Unique String) -> IO ()+    add tv = atomically $ do       m <- readTVar tv       writeTVar tv $ Map.insert u l m 
Control/Concurrent/CHP/Traces/CSP.hs view
@@ -32,7 +32,7 @@ module Control.Concurrent.CHP.Traces.CSP (CSPTrace(..), getCSPPlain, runCHP_CSPTrace, runCHP_CSPTraceAndPrint) where  import Control.Concurrent.STM-import Control.Monad.State+import Control.Monad (liftM) import qualified Data.Map as Map import Data.Unique import Text.PrettyPrint.HughesPJ@@ -54,10 +54,10 @@                         runCHPProgramWith' st (flip toPublic st) p    prettyPrint (CSPTrace (labels, events))-    = char '<' <+> sep (punctuate (char ',') $ evalState (mapM (liftM text . nameEvent) events) labels) <+> char '>'+    = char '<' <+> sep (punctuate (char ',') $ mapM (liftM text . nameEvent) events `labelWith` labels) <+> char '>'    labelAll (CSPTrace (labels, events))-    = CSPTrace (Map.empty, evalState (mapM nameEvent' events) labels)+    = CSPTrace (Map.empty, mapM nameEvent' events `labelWith` labels)  toPublic :: ChannelLabels Unique -> SubTraceStore -> IO (CSPTrace Unique) toPublic l (CSPTraceRev tv)
Control/Concurrent/CHP/Traces/Structural.hs view
@@ -38,7 +38,6 @@   getAllEventsInHierarchy) where  import Control.Applicative hiding (empty)-import Control.Monad.State import qualified Data.Foldable as F import Data.IORef import Data.List@@ -115,7 +114,7 @@    prettyPrint (StructuralTrace (_,Nothing)) = empty   prettyPrint (StructuralTrace (labels, Just h))-    = pp $ evalState (T.mapM nameIndivEvent h) labels+    = pp $ T.mapM nameIndivEvent h `labelWith` labels     where       pp :: EventHierarchy String -> Doc       pp (SingleEvent x) = text x@@ -129,7 +128,7 @@    labelAll (StructuralTrace (_, Nothing)) = StructuralTrace (Map.empty, Nothing)   labelAll (StructuralTrace (labels, Just h))-    = StructuralTrace (Map.empty, Just $ evalState (T.mapM nameIndivEvent' h) labels)+    = StructuralTrace (Map.empty, Just $ T.mapM nameIndivEvent' h `labelWith` labels)  toPublic :: ChannelLabels Unique -> SubTraceStore -> IO (StructuralTrace Unique) toPublic l (Hierarchy hv)
Control/Concurrent/CHP/Traces/VCR.hs view
@@ -34,7 +34,7 @@ module Control.Concurrent.CHP.Traces.VCR (VCRTrace(..), getVCRPlain, runCHP_VCRTrace, runCHP_VCRTraceAndPrint) where  import Control.Concurrent.STM-import Control.Monad.State+import Control.Monad (liftM) import qualified Data.Map as Map import qualified Data.Set as Set import Data.Unique@@ -63,13 +63,13 @@   prettyPrint (VCRTrace (labels, eventSets))     = char '<' <+> sep (punctuate (char ',') $ map (braces . sep . punctuate (char ',')) ropes) <+> char '>'     where-      es = evalState (mapM nameVCR eventSets) labels+      es = mapM nameVCR eventSets `labelWith` labels        ropes :: [[Doc]]       ropes = map (map text . Set.toList) es    labelAll (VCRTrace (labels, eventSets))-    = VCRTrace (Map.empty, evalState (mapM nameVCR' eventSets) labels)+    = VCRTrace (Map.empty, mapM nameVCR' eventSets `labelWith` labels)  toPublic :: ChannelLabels Unique -> SubTraceStore -> IO (VCRTrace Unique) toPublic l (VCRTraceRev tv)@@ -77,10 +77,10 @@        return $ VCRTrace (l, map (Set.map snd) $ reverse setList) toPublic _ _ = error "Error in VCR trace -- tracing type got switched" -nameVCR :: Ord u => Set.Set (RecordedEvent u) -> State (ChannelLabels u) (Set.Set String)+nameVCR :: Ord u => Set.Set (RecordedEvent u) -> LabelM u (Set.Set String) nameVCR = liftM Set.fromList . mapM nameEvent . Set.toList -nameVCR' :: Ord u => Set.Set (RecordedEvent u) -> State (ChannelLabels u) (Set.Set (RecordedEvent String))+nameVCR' :: Ord u => Set.Set (RecordedEvent u) -> LabelM u (Set.Set (RecordedEvent String)) nameVCR' = liftM Set.fromList . mapM nameEvent' . Set.toList  -- | A helper function for pulling out the interesting bit from a VCR trace processed
chp.cabal view
@@ -1,5 +1,5 @@ Name:            chp-Version:         2.1.0.1+Version:         2.2.0 Synopsis:        An implementation of concurrency ideas from Communicating Sequential Processes License:         BSD3 License-file:    LICENSE@@ -23,7 +23,7 @@  Cabal-Version:   >= 1.2.3 Build-Type:      Simple-Build-Depends:   base >= 3 && < 5, containers, deepseq >= 1.1 && < 1.2, extensible-exceptions >= 0.1.1.0, loop-while, mtl, pretty, stm+Build-Depends:   base >= 3 && < 5, containers, deepseq >= 1.1 && < 1.2, extensible-exceptions >= 0.1.1.0, pretty, stm  Exposed-modules: Control.Concurrent.CHP                  Control.Concurrent.CHP.Alt@@ -57,7 +57,7 @@                  Control.Concurrent.CHP.ProcessId                  Control.Concurrent.CHP.Traces.Base -Extensions:      BangPatterns CPP FlexibleInstances GeneralizedNewtypeDeriving-                 MultiParamTypeClasses ScopedTypeVariables +Extensions:      BangPatterns CPP FlexibleInstances+                 MultiParamTypeClasses Rank2Types ScopedTypeVariables  GHC-Options:     -Wall -auto-all