-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | An implementation of concurrency ideas from Communicating Sequential Processes -- -- The Communicating Haskell Processes (CHP) library is an implementation -- of message-passing concurrency ideas from Hoare's Communicating -- Sequential Processes. More details and a tutorial can be found at its -- homepage: http://www.cs.kent.ac.uk/projects/ofa/chp/, and there -- is also now a blog with examples of using the library: -- http://chplib.wordpress.com/. The library requires at least GHC -- 6.8.1. NOTE: since version 2.0.0, some capabilities that were present -- in version 1.x have been moved out to the chp-plus package. @package chp @version 2.1.0 -- | This module contains a proliferation of channel creation methods. -- -- For most uses, newChannel is the only method needed from this -- module. This creates a channel for you to use. The channel will be -- automatically destroyed during garbage collection when it falls out of -- use, so there is no need to do anything to destroy it. -- -- It is often possible for the type system to infer which channel you -- want when you use newChannel. If the types of the ends are -- known by the type system, the channel-type can be inferred. So you can -- usually just write newChannel, and depending on how you use the -- channel, the type system will figure out which one you needed. -- -- If this gives a type error along the lines of: -- --
--   Ambiguous type variables `r', `w' in the constraint:
--     `Channel r w' arising from a use of `newChannel' at tmp.hs:3:24-33
--   Probable fix: add a type signature that fixes these type variable(s)
--   
-- -- Then you must either explicitly type the channel ends you are using, -- or more simply, use one of the synonyms in -- Control.Concurrent.CHP.Channels.Synonyms to indicate which kind -- of channel you are allocating. -- -- Several other functions in this module, such as newChannelWR, -- newChannels and newChannelList are helpers built with -- newChannel to ease dealing with channel creation. -- -- The remainder of the functions in this module are related to traces -- (see Control.Concurrent.CHP.Traces), and allowing the channels -- to show up usefully in traces: see newChannel' and -- ChanOpts. -- -- The channel creation methods were refactored in version 1.5.0. Your -- code will only be affected if you were using the trace-related methods -- (for labelling the channels in traces). Instead of using -- oneToOneChannelWithLabel foo, you should use -- oneToOneChannel' $ chanLabel foo. module Control.Concurrent.CHP.Channels.Creation -- | A channel type, that can be used to get the ends of the channel via -- reader and writer data Chan r w a -- | A class used for allocating new channels, and getting the reading and -- writing ends. There is a bijective assocation between the channel, and -- its pair of end types. You can see the types in the list of instances -- below. Thus, newChannel may be used, and the compiler will -- infer which type of channel is required based on what end-types you -- get from reader and writer. Alternatively, if you -- explicitly type the return of newChannel, it will be definite -- which ends you will use. If you do want to fix the type of the channel -- you are using when you allocate it, consider using one of the many -- oneToOneChannel-like shorthand functions that fix the type. class Channel r w newChannel' :: (Channel r w, MonadCHP m) => ChanOpts a -> m (Chan r w a) sameChannel :: (Channel r w) => r a -> w a -> Bool -- | Allocates a new channel. Nothing need be done to destroy/de-allocate -- the channel when it is no longer in use. -- -- This function does not add any information to the traces: see -- newChannel' for that purpose. -- -- In version 1.5.0, this function was moved out of the Channel -- class, but that should only matter if you were declaring your own -- instances of that class (very unlikely). newChannel :: (MonadCHP m, Channel r w) => m (Chan r w a) -- | Options for channel creation; a function to show the inner data, and -- an optional label (both only affect tracing). These options can be -- passed to newChannel'. -- -- Added in version 1.5.0. data ChanOpts a ChanOpts :: Int -> (a -> String) -> Maybe String -> ChanOpts a -- | Added in version 2.1.0. Priority is per-event, static and system-wide. -- If it is possible at any given moment for a process to resolve a -- choice one of several ways, the channel/barrier with the highest -- priority is chosen. If the choice is a conjunction and all events in -- one conjunction are higher than all the events in the other, the -- higher one is chosen (otherwise no guarantees are made). The default -- is zero, and the range is the full range of Int (both positive and -- negative). chanOptsPriority :: ChanOpts a -> Int chanOptsShow :: ChanOpts a -> a -> String chanOptsLabel :: ChanOpts a -> Maybe String -- | The default: don't show anything, don't label anything -- -- Added in version 1.5.0. defaultChanOpts :: ChanOpts a -- | Uses the Show instance for showing the data in traces, and the given -- label. -- -- Added in version 1.5.0. chanLabel :: (Show a) => String -> ChanOpts a -- | A helper that is like newChannel but returns the writing and -- reading end of the channels directly. newChannelWR :: (Channel r w, MonadCHP m) => m (w a, r a) -- | 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) -- | 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 newChannels :: (ChannelTuple t, MonadCHP m) => m t -- | Creates a list of channels of the same type with the given length. If -- you need to access some channels by index, use this function. -- Otherwise you may find using newChannels to be easier. newChannelList :: (Channel r w, MonadCHP m) => Int -> m [Chan r w a] -- | A helper that is like newChannelList, but labels the channels -- with the given list. The number of channels returned is the same as -- the length of the list of labels newChannelListWithLabels :: (Channel r w, MonadCHP m) => [String] -> m [Chan r w a] -- | A helper that is like newChannelList, but labels the channels -- according to a pattern. Given a stem such as foo, it names the -- channels in the list foo0, foo1, foo2, etc. newChannelListWithStem :: (Channel r w, MonadCHP m) => Int -> String -> m [Chan r w a] -- | 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 () instance Channel (Shared Chanin) (Shared Chanout) instance Channel Chanin (Shared Chanout) instance Channel (Shared Chanin) Chanout instance Channel Chanin Chanout 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) 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) instance (Channel r w) => ChannelTuple (Chan r w a, Chan r w a, Chan r w a, Chan r w a) instance (Channel r w) => ChannelTuple (Chan r w a, Chan r w a, Chan r w a) instance (Channel r w) => ChannelTuple (Chan r w a, Chan r w a) module Control.Concurrent.CHP.Traces.TraceOff -- | A trace type that does not record anything. data TraceOff a -- | A type-constrained version of runCHPAndTrace. This is -- semantically identical to runCHP, but this function is useful -- with the qcCHP' function in the testing module. runCHP_TraceOff :: CHP a -> IO (Maybe a, TraceOff Unique) instance Trace TraceOff instance Show (TraceOff a) -- | This module contains support for CSP-style tracing. A CSP trace is -- simply a flat list of events in the order in which they occurred. module Control.Concurrent.CHP.Traces.CSP -- | A classic CSP trace. It is simply the channel labels, and a list of -- recorded events in sequence -- the head of the list is the first -- (oldest) event. newtype CSPTrace u CSPTrace :: (ChannelLabels u, [RecordedEvent u]) -> CSPTrace u -- | A helper function for pulling out the interesting bit from a CSP trace -- processed by labelAll. -- -- Added in version 1.5.0. getCSPPlain :: CSPTrace String -> [RecordedEvent String] runCHP_CSPTrace :: CHP a -> IO (Maybe a, CSPTrace Unique) runCHP_CSPTraceAndPrint :: CHP a -> IO () instance Trace CSPTrace instance (Ord u) => Show (CSPTrace u) -- | This module contains support for structural traces. Structural traces -- reflect the parallel composition of your program. Effectively, each -- process records its own local trace. Parallel traces are then merged -- as parallel compositions, and you end up with a big tree of -- sequentially and parallel-composed traces. Note that in this tracing -- style, unlike CSP and VCR, events are recorded by every process -- involved in them, not just once per occurrence. module Control.Concurrent.CHP.Traces.Structural -- | A nested (or hierarchical) trace. The trace is an event hierarchy, -- wrapped in a Maybe type to allow for representation of the empty trace -- (Nothing). newtype StructuralTrace u StructuralTrace :: (ChannelLabels u, Maybe (EventHierarchy (RecordedIndivEvent u))) -> StructuralTrace u -- | A data type representing a hierarchy of events. The count on the -- StructuralSequence count is a replicator count for that list of -- sequential items. -- -- The Show, Read, Foldable and Traversable instances were added in -- version 1.3.0. -- -- The Eq instance was added in version 1.5.0. data EventHierarchy a SingleEvent :: a -> EventHierarchy a StructuralSequence :: Int -> [EventHierarchy a] -> EventHierarchy a StructuralParallel :: [EventHierarchy a] -> EventHierarchy a -- | A helper function for pulling out the interesting bit from a -- Structural trace processed by labelAll. -- -- Added in version 1.5.0. getStructuralPlain :: StructuralTrace String -> Maybe (EventHierarchy (RecordedIndivEvent String)) runCHP_StructuralTrace :: CHP a -> IO (Maybe a, StructuralTrace Unique) runCHP_StructuralTraceAndPrint :: CHP a -> IO () -- | Flattens the events into a list. The resulting list may contain -- duplicates, and it should not be assumed that the order relates in any -- way to the original hierarchy. getAllEventsInHierarchy :: EventHierarchy a -> [a] instance (Show a) => Show (EventHierarchy a) instance (Read a) => Read (EventHierarchy a) instance Trace StructuralTrace instance (Ord u) => Show (StructuralTrace u) instance Traversable EventHierarchy instance Foldable EventHierarchy instance Functor EventHierarchy instance (Eq a) => Eq (EventHierarchy a) -- | A module for recording View Centric Reasoning (VCR) traces. A view -- centric reasnoning trace is a list of sets of events. Each set -- contains independent events that have no causal relationship between -- them. Hopefully we will publish a paper explaining all this in detail -- soon. module Control.Concurrent.CHP.Traces.VCR -- | A VCR (View-Centric Reasoning) trace. It is the channel labels, -- accompanied by a sequential list of sets of recorded events. Each of -- the sets is a set of independent events. The set at the head of the -- list is the first-recorded (oldest). -- -- The type became parameterised in version 1.3.0 newtype VCRTrace u VCRTrace :: (ChannelLabels u, [Set (RecordedEvent u)]) -> VCRTrace u -- | A helper function for pulling out the interesting bit from a VCR trace -- processed by labelAll. -- -- Added in version 1.5.0. getVCRPlain :: VCRTrace String -> [Set (RecordedEvent String)] runCHP_VCRTrace :: CHP a -> IO (Maybe a, VCRTrace Unique) runCHP_VCRTraceAndPrint :: CHP a -> IO () instance Trace VCRTrace instance (Ord u) => Show (VCRTrace u) -- | A module that re-exports all the parts of the library related to -- tracing. -- -- The idea of tracing is to record the concurrent events (i.e. channel -- communications and barrier synchronisations) that occur during a run -- of the program. You can think of it as automatically turning on a lot -- of debug logging. -- -- Typically, at the top-level of your program you should have: -- --
--   main :: IO ()
--   main = runCHP myMainProcess
--   
-- -- To turn on the tracing mechanism of your choice (for example, -- CSP-style tracing) to automatically print out the trace after -- completion of your program, just use the appropriate helper function: -- --
--   main :: IO ()
--   main = runCHP_CSPTraceAndPrint myMainProcess
--   
-- -- It could hardly be easier. If you want more fine-grained control and -- examination of the trace, you can use the helper functions of the form -- runCHP_CSPTrace that give back a data structure representing -- the trace, which you can then manipulate. -- -- The Doc used by the traces is from the -- Text.PrettyPrint.HughesPJ module that currently comes with -- GHC (I think). -- -- For more details on the theory behind the tracing, the logic behind -- its implementation, and example traces, see the paper "Representation -- and Implementation of CSP and VCR Traces", N.C.C. Brown and M.L. -- Smith, CPA 2008. An online version can be found at: -- http://twistedsquare.com/Traces.pdf module Control.Concurrent.CHP.Traces -- | A globally recorded event, found in CSP and VCR traces. Either a -- channel communication (with a unique identifier of the channel) or a -- barrier synchronisation (with a unique identifier of the barrier). The -- identifiers are per channel/barrier, not per event. Currently, -- channels and barriers can never have the same Unique as each other, -- but do not rely on this behaviour. -- -- The type became parameterised in version 1.3.0. type RecordedEvent u = (RecordedEventType, u) type ChannelLabels u = Map u String -- | The type of an event in the CSP and VCR traces. -- -- ClockSync was added in version 1.2.0. -- -- The extra parameter on ChannelComm and BarrierSync (which are the -- result of showing the value sent and phase ended respectively) was -- added in version 1.5.0. data RecordedEventType ChannelComm :: String -> RecordedEventType BarrierSync :: String -> RecordedEventType ClockSync :: String -> RecordedEventType -- | An individual record of an event, found in nested traces. Either a -- channel write or read, or a barrier synchronisation, each with a -- unique identifier for the barrier/channel. The event will be recorded -- by everyone involved, and a ChannelWrite will have the same channel -- identifier as the corresponding channel-read. The identifiers are per -- channel/barrier, not per event. Currently, channels and barriers can -- never have the same Unique as each other, but do not rely on this -- behaviour. -- -- The type u item is the unique identifier of the -- channelbarrierclock, and the Integer is a sequence identifier -- for that channelbarrierclock (first sync is 0, second sync is -- 1, etc), and finally the String shows the -- value-sentphase-endedtime involved. -- -- ClockSyncIndiv was added in version 1.2.0. -- -- The type became parameterised, and the Show and Read instances were -- added in version 1.3.0. -- -- The String parameters on ChannelWrite, ChannelRead and -- BarrierSyncIndiv were added in version 1.5.0. data RecordedIndivEvent u ChannelWrite :: u -> Integer -> String -> RecordedIndivEvent u ChannelRead :: u -> Integer -> String -> RecordedIndivEvent u BarrierSyncIndiv :: u -> Integer -> String -> RecordedIndivEvent u ClockSyncIndiv :: u -> Integer -> String -> RecordedIndivEvent u -- | Added in version 1.3.0. recordedIndivEventLabel :: RecordedIndivEvent u -> u -- | Added in version 1.3.0. recordedIndivEventSeq :: RecordedIndivEvent u -> Integer -- | A class representing a type of trace. The main useful function is -- runCHPAndTrace, but because its type is only determined by its -- return type, you may wish to use the already-typed functions offered -- in each trace module -- see the modules in -- Control.Concurrent.CHP.Traces. -- -- The trace type involved became parameterised in version 1.3.0. class Trace t runCHPAndTrace :: (Trace t) => CHP a -> IO (Maybe a, t Unique) emptyTrace :: (Trace t) => t u prettyPrint :: (Trace t, Ord u) => t u -> Doc labelAll :: (Trace t, Ord u) => t u -> t String -- | Takes a VCR trace and forms all the possible CSP traces (without -- duplicates) that could have arisen from the same execution. -- -- This is done by taking all permutations of each set in the VCR trace -- (which is a list of sets) and concatenating them with the results of -- the same process on the rest of the trace. Thus the maximum size of -- the returned set of CSP traces is the product of the sizes of all the -- non-empty sets in the VCR trace. -- -- This function was added in version 1.5.0. vcrToCSP :: (Eq u) => VCRTrace u -> [CSPTrace u] -- | Takes a structural trace and forms all the possible CSP traces -- (without duplicates) that could have arisen from the same execution. -- -- This is done -- roughly speaking -- by replaying the structural trace -- in all possible execution orderings and pulling out the CSP trace for -- each ordering. -- -- It should be the case for all structural traces t that do not -- use conjunction (every and '(<&>)'): -- --
--   structuralToCSP t =~= (concatMap vcrToCSP . structuralToVCR) t
--     where a =~= b = or [a' == b' | a' <- permutations a, b' <- permutations  b]
--   
-- -- This function was added in version 1.5.0. structuralToCSP :: (Ord u) => StructuralTrace u -> [CSPTrace u] -- | Takes a structural trace and forms all the possible VCR traces -- (without duplicates) that could have arisen from the same execution. -- -- This is done -- roughly speaking -- by replaying the structural trace -- in all possible execution orderings and pulling out the VCR trace for -- each ordering. -- -- This function was added in version 1.5.0. structuralToVCR :: (Ord u) => StructuralTrace u -> [VCRTrace u] instance Monoid (Cont u) module Control.Concurrent.CHP.Parallel -- | This type-class supports parallel composition of processes. You may -- use the runParallel function to run a list of processes, or the -- <||> operator to run just a pair of processes. -- -- In each case, the composition waits for all processes to finish, -- either successfully or with poison. At the end of this, if any -- process exited with poison, the composition will "rethrow" this -- poison. If all the processes completed successfully, the results will -- be returned. If you want to ignore poison from the sub-processes, use -- an empty poison handler and onPoisonTrap with each branch. -- -- Runs the given list of processes in parallel, and then returns a list -- of the results, in the same order as the processes given. Will only -- return when all the inner processes have completed. -- -- In version 1.5.0, a bug was introduced such that runParallel -- [] would deadlock; this was fixed in version 1.5.1. runParallel :: [CHP a] -> CHP [a] -- | Runs all the given processes in parallel and discards any output. Does -- not return until all the processes have completed. runParallel_ -- ps is effectively equivalent to runParallel ps >> return -- (). -- -- In version 1.5.0, a bug was introduced such that runParallel_ -- [] would deadlock; this was fixed in version 1.5.1. runParallel_ :: [CHP a] -> CHP () -- | A useful operator for performing a two process equivalent of -- runParallel that gives the return values back as a pair rather -- than a list. This also allows the values to have different types (<||>) :: CHP a -> CHP b -> CHP (a, b) -- | An operator similar to <||> that discards the output -- (more like an operator version of runParallel_). -- -- Added in version 1.1.0. (<|*|>) :: CHP a -> CHP b -> CHP () -- | A shorthand for applying mapM in parallel; really the composition of -- runParallel and map. -- -- Added in version 1.5.0. runParMapM :: (a -> CHP b) -> [a] -> CHP [b] -- | A shorthand for applying mapM_ in parallel; really the composition of -- runParallel_ and map. -- -- Added in version 1.5.0. runParMapM_ :: (a -> CHP b) -> [a] -> CHP () -- | A monad transformer used for introducing forking blocks. data (Monad m, MonadCHP m) => ForkingT m a -- | 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 the processes terminated with uncaught poison. If they -- did, the poison is propagated (rethrown). forking :: (MonadCHP m) => ForkingT m a -> m a -- | Forks off the given process. The process then runs in parallel with -- this code, until the end of the forking block, when all -- forked-off processes 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 () instance (Monad m) => Monad (ForkingT m) instance (MonadIO m) => MonadIO (ForkingT m) instance MonadTrans ForkingT instance (MonadCHP m) => MonadCHP (ForkingT m) -- | This module contains all the central monads in the CHP library. module Control.Concurrent.CHP.Monad -- | The central monad of the library. You can use -- Control.Concurrent.CHP.Monad.runCHP and -- Control.Concurrent.CHP.Monad.runCHP_ to execute programs in -- this monad. data CHP a -- | 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 liftCHP :: (MonadCHP m) => CHP a -> m a -- | Runs a CHP program. You should use this once, at the top-level of your -- program. Do not ever use this function twice in parallel and attempt -- to communicate between those processes using channels. Instead, run -- this function once and use it to spawn off the parallel processes that -- you need. runCHP :: CHP a -> IO (Maybe a) -- | Runs a CHP program. Like runCHP but discards the output. runCHP_ :: CHP a -> IO () -- | 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 is -- an IO action that you can now use in the IO monad wherever you like. -- What it returns is the result of your original action. -- -- This function is intended for use wherever you need to supply an IO -- callback (for example with the OpenGL libraries) that needs to perform -- CHP communications. It is the safe way to do things, rather than using -- runCHP twice (and also works with CSP and VCR traces -- but not -- structural traces!). embedCHP :: CHP a -> CHP (IO (Maybe a)) -- | A convenient version of embedCHP that ignores the result embedCHP_ :: CHP a -> CHP (IO ()) -- | A helper like embedCHP for callbacks that take an argument embedCHP1 :: (a -> CHP b) -> CHP (a -> IO (Maybe b)) -- | A convenient version of embedCHP1 that ignores the result embedCHP1_ :: (a -> CHP b) -> CHP (a -> IO ()) -- | Allows you to provide a handler for sections with poison. It is -- usually used in an infix form as follows: -- --
--   (readChannel c >>= writeChannel d) `onPoisonTrap` (poison c >> poison d)
--   
-- -- It handles the poison and does not rethrow it (unless your handler -- does so). If you want to rethrow (and actually, you'll find you -- usually do), use onPoisonRethrow onPoisonTrap :: CHP a -> CHP a -> CHP a -- | 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 -- re-thrown after the handler anyway. That is, the following lines of -- code all have identical behaviour: -- --
--   foo
--   foo `onPoisonRethrow` throwPoison
--   foo `onPoisonRethrow` return ()
--   
onPoisonRethrow :: CHP a -> CHP () -> CHP a -- | Throws a poison exception. throwPoison :: CHP a -- | A class indicating that something is poisonable. class Poisonable c poison :: (Poisonable c, MonadCHP m) => c -> m () checkForPoison :: (Poisonable c, MonadCHP m) => c -> m () -- | Poisons all the given items. A handy shortcut for mapM_ -- poison. poisonAll :: (Poisonable c, MonadCHP m) => [c] -> m () -- | The classic skip process/guard. Does nothing, and is always ready. -- -- Suitable for use in an Control.Concurrent.CHP.Alt.alt. skip :: CHP () -- | 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 -- | Waits for the specified number of microseconds (millionths of a -- second). There is no guaranteed precision, but the wait will never -- complete in less time than the parameter given. -- -- Suitable for use in an Control.Concurrent.CHP.Alt.alt, but -- note that waitFor 0 is not the same as skip. -- waitFor 0 Control.Concurrent.CHP.Alt.</> x will -- not always select the first guard, depending on x. Included in this is -- the lack of guarantee that waitFor 0 -- Control.Concurrent.CHP.Alt.</> waitFor n will -- select the first guard for any value of n (including 0). It is not -- useful to use two waitFor guards in a single -- Control.Concurrent.CHP.Alt.alt anyway. -- -- 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 () -- | A module with support for things that are enrollable (barriers and -- broadcast channels). module Control.Concurrent.CHP.Enroll -- | 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 based on a single enroll call, undefined -- behaviour will result. data Enrolled b a class Enrollable b z enroll :: (Enrollable b z) => b z -> (Enrolled b z -> CHP a) -> CHP a resign :: (Enrollable b z) => Enrolled b z -> CHP a -> CHP a -- | Just like enroll, but starts with an already enrolled item. During the -- body, you are enrolled twice -- once from the original enrolled item -- (which is still valid in the body) and once from the new enrolled item -- passed to the inner function. Afterwards, you are enrolled once, on -- the original item you had. -- -- This function was added in version 1.3.2. furtherEnroll :: (Enrollable b z) => Enrolled b z -> (Enrolled b z -> CHP a) -> CHP a -- | Like enroll but enrolls on the given pair of barriers enrollPair :: (Enrollable b p, Enrollable b' p') => (b p, b' p') -> ((Enrolled b p, Enrolled b' p') -> CHP a) -> CHP a -- | Like enroll but enrolls on the given list of barriers enrollList :: (Enrollable b p) => [b p] -> ([Enrolled b p] -> CHP a) -> CHP a -- | Given a command to allocate a new barrier, and a list of processes -- that use that barrier, enrolls the appropriate number of times (i.e. -- the list length) and runs all the processes in parallel using that -- barrier, then returns a list of the results. -- -- If you have already allocated the barrier, pass return bar as -- the first parameter. -- -- Added in version 1.7.0. enrollAll :: (Enrollable b p) => CHP (b p) -> [Enrolled b p -> CHP a] -> CHP [a] -- | Like enrollAll, but discards the results. -- -- Added in version 1.7.0. enrollAll_ :: (Enrollable b p) => CHP (b p) -> [Enrolled b p -> CHP a] -> CHP () enrollAllT :: (Enrollable b p) => ([a] -> CHP c) -> CHP (b p) -> [Enrolled b p -> a] -> CHP c enrollOneMany :: (Enrollable b p) => ([Enrolled b p] -> CHP a) -> [(CHP (b p), Enrolled b p -> CHP c)] -> CHP (a, [c]) -- | 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: -- -- -- -- Examples of events that do NOT support alting are: -- -- -- -- 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. -- -- Here are some examples of using alting: -- -- -- --
--   liftM Just (readChannel c) <-> (waitFor 1000000 >> return Nothing)
--   
-- -- -- --
--   liftM Just (readChannel c) </> (skip >> return Nothing)
--   
-- -- -- --
--   readChannel c0 <-> readChannel c1
--   
-- -- -- --
--   (readChannel c >>= writeChannel d) </> skip
--   
-- -- Note that if you wait for a sequential composition: -- --
--   (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 -- | An alt between several actions, with arbitrary priority. The first -- available action is chosen (with an arbitrary choice if many actions -- are available at the same time), its body run, and its value returned. alt :: [CHP a] -> CHP a -- | 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 foldl1 (<->) (<->) :: CHP a -> CHP a -> CHP a -- | 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. --
  3. time-out guards (such as waitFor)
  4. --
  5. dummy guards (skip and stop)
  6. --
-- -- 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 -- 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 -- | A useful operator to perform a priAlt. This operator is -- associative, and has descending priority (that is, it is left-biased). -- When you have lots of actions, it is probably easier to use the -- priAlt function. priAlt may be more efficent than -- foldl1 (</>) () :: CHP a -> CHP a -> CHP a -- | Runs all the given processes in parallel with each other, but only -- when the choice at the beginning of each item is ready. -- -- So for example, if you do: -- --
--   every [ readChannel c >>= writeChannel d, readChannel e >>= writeChannel f]
--   
-- -- This will forward values from c and e to d and f respectively in -- parallel, but only once both channels c and e are ready to be read -- from. So f cannot be written to before c is read from (contrast this -- with what would happen if every were replaced with -- runParallel). -- -- This behaviour can be somewhat useful, but every is much more -- powerful when used as part of an alt. This code: -- --
--   alt [ every [ readChannel c, readChannel d]
--       , every [ writeChannel e 6, writeChannel f 8] ]
--   
-- -- Waits to either read from channels c and d, or to write to channels e -- and f. -- -- The events involved can partially overlap, e.g. -- --
--   alt [ every [ readChannel a, readChannel b]
--       , every [ readChannel a, writeChannel c 6] ]
--   
-- -- This will wait to either read from channels a and b, or to read from a -- and write to c, whichever combination is ready first. If both are -- ready, the choice between them will be arbitrary (just as with any -- other choices; see alt for more details). -- -- The sets can even be subsets of each other, such as: -- --
--   alt [ every [ readChannel a, readChannel b]
--       , every [ readChannel a, readChannel b, readChannel b] ]
--   
-- -- In this case there are no guarantees as to which choice will happen. -- Do not assume it will be the smaller, and do not assume it will be the -- larger. -- -- Be wary of what happens if a single event is included multiple times -- in the same every, as this may not do what you expect (with or -- without choice). Consider: -- --
--   every [ readChannel c >> writeChannel d 6
--         , readChannel c >> writeChannel d 8 ]
--   
-- -- What will happen is that the excecution will wait to read from c, but -- then it will execute only one of the bodies (an arbitrary choice). In -- general, do not rely on this behaviour, and instead try to avoid -- having the same events in an every. Also note that if you -- synchronise on a barrier twice in an every, this will only -- count as one member enrolling, even if you have two enrolled ends! For -- such a use, look at runParallel instead. -- -- Also note that this currently applies to both ends of channels, so -- that: -- --
--   every [ readChannel c, writeChannel c 2 ]
--   
-- -- Will block indefinitely, rather than completing the communication. -- -- Each item every must support choice (and in fact only a subset -- of the items supported by alt are supported by every). -- Currently the items in the list passed to every must be one of -- the following: -- -- -- -- Timeouts (e.g. waitFor) are currently not supported. You can -- always get another process to synchronise on an event with you once a -- certain time has passed. -- -- Note also that you cannot put an alt inside an every. So -- you cannot say: -- --
--   every [ readChannel c
--         , alt [ readChannel d, readChannel e ] ]
--   
-- -- To wait for c and (d or e) like this you must expand it out into (c -- and d) or (c and e): -- --
--   alt [ every [ readChannel c, readChannel d]
--       , every [ readChannel c, readChannel e] ]
--   
-- -- As long as x meets the conditions laid out above, every [x] -- will have the same behaviour as x. -- -- Added in version 1.1.0 every :: [CHP a] -> CHP [a] -- | Like every but discards the results. -- -- Added in version 1.8.0. every_ :: [CHP a] -> CHP () -- | A useful operator that acts like every. The operator is -- associative and commutative (see every for notes on -- idempotence). When you have lots of things to join with this operator, -- it's probably easier to use the every function. -- -- Added in version 1.1.0 (<&>) :: CHP a -> CHP b -> CHP (a, b) -- | A module containing barriers. -- -- A barrier is a synchronisation primitive. When N processes are -- enrolled on a barrier, all N must synchronise on the barrier before -- any synchronisations may complete, at which point they all complete. -- That is, when a single process synchronises on a barrier, it must then -- wait until all the other enrolled processes also synchronise before it -- can finish. -- -- Only processes enrolled on a barrier may synchronise on it. Enrolled -- barriers should not be passed around between processes, or used twice -- in a parallel composition. Instead, each process should enroll on the -- barrier itself. -- -- Barriers support choice (alting). This can lead to a lot of -- non-determinism and some confusion. Consider these two processes, both -- enrolled on barriers a and b: -- --
--   (sync a <-> sync b)
--   (sync b <-> sync a)
--   
-- -- Which barrier completes is determined by the run-time, and will be an -- arbitrary choice. This is even the case when priority is involved: -- --
--   (sync a </> sync b)
--   (sync b </> sync a)
--   
-- -- Clearly there is no way to resolve this to satisfy both priorities; -- the run-time will end up choosing. -- -- Barrier poison can be detected when syncing, enrolling or resigning. -- You may only poison a barrier that you are currently enrolled on. -- -- Barriers can also support phases. The idea behind a phased barrier is -- that a barrier is always on a certain phase P. Whenever a barrier -- successfully completes, the phase is incremented (but it does not have -- to be an integer). Everyone is told the new phase once they complete a -- synchronisation, and may query the current phase for any barrier that -- they are currently enrolled on. module Control.Concurrent.CHP.Barriers -- | A special case of the PhasedBarrier that has no useful phases, i.e. a -- standard barrier. type Barrier = PhasedBarrier () -- | A useful type synonym for enrolled barriers with no phases -- -- Added in 1.1.0 type EnrolledBarrier = Enrolled PhasedBarrier () -- | Creates a new barrier with no processes enrolled newBarrier :: CHP Barrier -- | Creates a new barrier with no processes enrolled and the given -- priority. -- -- Added in version 2.1.0. newBarrierPri :: Int -> CHP Barrier -- | Creates a new barrier with no processes enrolled and labels it in -- traces using the given label. See newBarrier. newBarrierWithLabel :: String -> CHP Barrier -- | A phased barrier that is capable of being poisoned and throwing -- poison. You will need to enroll on it to do anything useful with it. -- For the phases you can use any type that satisfies Enum, -- Bounded and Eq. The phase increments every time the -- barrier completes. Incrementing consists of: if p == maxBound then -- minBound else succ p. Examples of things that make sense for -- phases: -- -- data PhasedBarrier phase -- | Creates a new barrier with no processes enrolled, that will be on the -- given phase. You will often want to pass in the last value in your -- phase cycle, so that the first synchronisation moves it on to the -- first -- -- The Show constraint was added in version 1.5.0 newPhasedBarrier :: (Enum phase, Bounded phase, Eq phase, Show phase) => phase -> CHP (PhasedBarrier phase) -- | Like newPhasedBarrier but allows you to customise the options. newPhasedBarrier' :: phase -> BarOpts phase -> CHP (PhasedBarrier phase) -- | Options for barrier creation; a function to show the inner data, and -- an optional label (both only affect tracing). These options can be -- passed to newPhasedBarrier'. -- -- Added in version 1.7.0. data BarOpts phase BarOpts :: (phase -> phase) -> Int -> (phase -> String) -> Maybe String -> BarOpts phase -- | Aside from the standard defaultIncPhase, you can use succ or -- (+1) with Integer as the inner type to get a barrier that never -- cycles. You can also do things like supplying (+2) as the incrementing -- function, or even using lists as the phase type to do crazy things. barIncPhase :: BarOpts phase -> phase -> phase -- | Added in version 2.1.0. See -- Control.Concurrent.CHP.Channels.Creation.ChanOpts. barPriority :: BarOpts phase -> Int barOptsShow :: BarOpts phase -> phase -> String barOptsLabel :: BarOpts phase -> Maybe String -- | The default phase incrementing function. If the phase is already at -- maxBound, it sets it to minBound; otherwise it uses -- succ to increment the phase. defaultIncPhase :: (Enum phase, Bounded phase, Eq phase) => phase -> phase -- | The default: don't show anything, don't label anything, use -- Enum+Bounded+Eq to work out the phase increment. -- -- Added in version 1.7.0. defaultBarOpts :: (Enum phase, Bounded phase, Eq phase) => BarOpts phase -- | Uses the Show instance for showing the data in traces, and the given -- label. -- -- Added in version 1.7.0. barLabel :: (Enum phase, Bounded phase, Eq phase, Show phase) => String -> BarOpts phase -- | Finds out the current phase a barrier is on. currentPhase :: Enrolled PhasedBarrier phase -> CHP phase -- | If the barrier is not in the given phase, synchronises on the barrier -- repeatedly until it is in the given phase. waitForPhase :: (Eq phase) => phase -> Enrolled PhasedBarrier phase -> CHP () -- | Synchronises on the barrier at least once, until it is in the given -- phase. -- -- Note that syncAndWaitForPhase ph bar == syncBarrier bar >> -- waitForPhase ph bar. -- -- Added in version 1.7.0. syncAndWaitForPhase :: (Eq phase) => phase -> Enrolled PhasedBarrier phase -> CHP () -- | Synchronises on the given barrier. You must be enrolled on a barrier -- in order to synchronise on it. Returns the new phase, following the -- synchronisation. syncBarrier :: Enrolled PhasedBarrier phase -> CHP phase -- | Gets the identifier of a Barrier. Useful if you want to identify it in -- the trace later on. getBarrierIdentifier :: PhasedBarrier ph -> Unique -- | Clocks, based on an idea by Adam Sampson. -- -- A clock is similar to a timer, but it is entirely concerned with -- logical time, rather than any relation to actual time, and all clocks -- are entirely independent. A clock has the concept of enrollment, so at -- any time there are N processes enrolled on the clock. Each process may -- wait on the clock for a specific time. Once all N enrolled processes -- are waiting for a time (giving a list of times Ts), the clock moves -- forward to the next time in Ts. -- -- Let's consider an example. Three processes are enrolled on an Int -- clock. The current time of the clock is 0. One process asks to wait -- for time 3, and blocks. A second process asks to wait for time 5, and -- blocks. Finally, the third process waits for time 3. At this point, -- the first and third process are free to proceed, and the new clock -- time is 3. The second process (waiting for time 5) stays waiting until -- the two processes have returned and waited again. -- -- There is also the option to wait for the next available time. If our -- two enrolled processes wait again, with the first waiting for time 7, -- and the third waiting for the next available time, the second and -- third will wake up, with the new time on the clock being 5 (the first -- stays waiting for time 7). -- -- There is also the ability for time to wrap around. If all -- processes are waiting for a time that is before the current -- time (using less-than from the Ord instance) or just the next -- available time, the earliest time of those will be taken. So if the -- current time is 26, and the processes are waiting for 11, 21 and next -- available time, the first and third will wake up and the new time will -- be 11. This is particularly useful for using your own algebraic type -- (data Phase = PhaseA | PhaseB | PhaseC deriving (Eq, Ord)). -- If you want to, you can use Integer and never use the time wrapping -- ability (see waitUnbounded). -- -- What the units of a clock mean is entirely up to you. The only -- requirement is an Ord instance for comparing two times, to use the -- above rules. The item in a clock may be an Int, a Double, an Integer, -- or even types like Bool or Either, your own types or newtypes, or -- things like lists! -- -- The following rules apply to clocks: -- -- -- -- Clocks are similar to phased barriers (indeed, both have an instance -- of Waitable). The fundamental differences are: -- -- -- -- This whole module was first added in version 1.2.0. module Control.Concurrent.CHP.Clocks -- | A clock that measures time using the given type. Only Ord is required -- on the type, so it can be all sorts. Obvious possibilities are numeric -- types such as Int and Double -- if you want monotonically-increasing -- time, see waitUnbounded. Other possibilities include your own -- algebraic types, if you want a clock that cycles around a given set of -- phases. If every process enrolled on the clock always just waits for -- the next time, you may want to consider using a PhasedBarrier. -- If you want a clock that works in reverse or anything else strange, -- you can always wrap your type in a newtype to give a custom Ord -- instance. -- -- See the documentation at the beginning of this module for more -- information on clocks. data (Ord time) => Clock time -- | A type-class for things that you can on for a specific time/phase. The -- instance for PhasedBarrier repeatedly syncs until the specific -- phase is reached. Clock waits until the time is reached. class Waitable c wait :: (Waitable c, Ord t) => Enrolled c t -> Maybe t -> CHP t getCurrentTime :: (Waitable c, Ord t) => Enrolled c t -> CHP t -- | Normally, when waiting on a clock, if you wait for a time equal to (or -- earlier than) the current time, you will block until the clock wraps -- around. Sometimes, however, you may want your clock to never wrap -- around (and use Integer as the inner type, usually), and want to make -- sure that if a process waits for the current time or earlier, it -- returns instantly. That is what this function achieves. -- -- Calling this function with Nothing has indentical behaviour to calling -- wait with Nothing. If you wait for the current time or earlier, -- all of the other processes waiting on the clock will remain blocked. -- Processes who have asked to wait for the current time will remain -- blocked -- it is generally not useful to mix waitUnbounded and -- wait on the same clock. waitUnbounded :: (Waitable c, Ord t) => Enrolled c t -> Maybe t -> CHP t -- | Creates a clock that starts at the given time. The Show instance is -- needed to display times in traces. newClock :: (Ord time, Show time) => time -> CHP (Clock time) -- | 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) instance (Ord time) => Poisonable (Enrolled Clock time) instance Waitable Clock instance (Ord time) => Enrollable Clock time instance Waitable PhasedBarrier -- | Channels in CHP must be used via their ends. It is generally these -- ends that you pass around to processes that want to communicate on the -- channel -- thus it is possible to see from the type -- ('Chanin'\/'Chanout') whether the process will use it for reading or -- writing. The channel-ends are named from the perspective of processes: -- a Chanin is a channel-end that a process may input values from, -- whereas a Chanout is a channel-end that a process may output values -- to. module Control.Concurrent.CHP.Channels.Ends -- | A reading channel-end type. -- -- See reader to obtain one, and ReadableChannel for how -- to use one. -- -- Eq instance added in version 1.1.1 data Chanin a -- | A writing channel-end type. -- -- See writer to obtain one, and WritableChannel for how -- to use one. -- -- Eq instance added in version 1.1.1 data Chanout a -- | A wrapper (usually around a channel-end) indicating that the inner -- item is shared. Use the claim function to use this type. data Shared c a -- | Gets the reading end of a channel from its Chan type. reader :: Chan r w a -> r a -- | Gets the writing end of a channel from its Chan type. writer :: Chan r w a -> w a -- | Gets all the reading ends of a list of channels. A shorthand for -- map reader. readers :: [Chan r w a] -> [r a] -- | Gets all the writing ends of a list of channels. A shorthand for -- map writer. writers :: [Chan r w a] -> [w a] -- | Claims the given channel-end, executes the given block, then releases -- the channel-end and returns the output value. If poison or an IO -- exception is thrown inside the block, the channel is released and the -- poison/exception re-thrown. claim :: Shared c a -> (c a -> CHP b) -> CHP b -- | A module containing some useful type synonyms for dealing with -- channels. -- -- If you get a type error such as: -- --
--   Ambiguous type variables `r', `w' in the constraint:
--     `Channel r w' arising from a use of `newChannel' at tmp.hs:3:24-33
--   Probable fix: add a type signature that fixes these type variable(s)
--   
-- -- Then you may want to substitute your use of newChannel for -- oneToOneChannel (if you are not using channel sharing). module Control.Concurrent.CHP.Channels.Synonyms type OneToOneChannel = Chan Chanin Chanout -- | A type-constrained version of newChannel. oneToOneChannel :: (MonadCHP m) => m (OneToOneChannel a) -- | A type-constrained version of newChannel'. -- -- Added in version 1.5.0. oneToOneChannel' :: (MonadCHP m) => ChanOpts a -> m (OneToOneChannel a) type OneToAnyChannel = Chan (Shared Chanin) (Chanout) -- | A type-constrained version of newChannel. oneToAnyChannel :: (MonadCHP m) => m (OneToAnyChannel a) -- | A type-constrained version of newChannel'. -- -- Added in version 1.5.0. oneToAnyChannel' :: (MonadCHP m) => ChanOpts a -> m (OneToAnyChannel a) type AnyToOneChannel = Chan (Chanin) (Shared Chanout) -- | A type-constrained version of newChannel. anyToOneChannel :: (MonadCHP m) => m (AnyToOneChannel a) -- | A type-constrained version of newChannel'. -- -- Added in version 1.5.0. anyToOneChannel' :: (MonadCHP m) => ChanOpts a -> m (AnyToOneChannel a) type AnyToAnyChannel = Chan (Shared Chanin) (Shared Chanout) -- | A type-constrained version of newChannel. anyToAnyChannel :: (MonadCHP m) => m (AnyToAnyChannel a) -- | A type-constrained version of newChannel'. -- -- Added in version 1.5.0. anyToAnyChannel' :: (MonadCHP m) => ChanOpts a -> m (AnyToAnyChannel a) -- | All the channel-ends in CHP are instances of ReadableChannel -- (for ends that you can read from) or WriteableChannel (for ends -- that you can write to). -- -- The readChannel and writeChannel functions are the -- standard way to communicate on a channel. These functions wait for the -- other party in the communication to arrive, then exchange the data, -- then complete. In pseudo-code, the semantics are like this when two -- parties (shown here as two columns) communicate: -- --
--   do sync                          sync
--      x                        <-   return y
--      done                          done
--   
-- -- Further options are offered by the extReadChannel and -- extWriteChannel channels, which allow either side to perform -- additional (so-called extended) actions during the communication. The -- semantics when both sides are performing extended actions are: -- --
--   do sync                          sync
--                                    y <- extWriteAction
--      x                        <-   return y
--      x' <- extReadAction x         done
--      done                          done
--      return x'
--   
-- -- Neither end need know that the other is performing an extended action, -- and any combination is possible (e.g. a normal writeChannel -- with an extReadChannel). module Control.Concurrent.CHP.Channels.Communication -- | A class indicating that a channel can be read from. class ReadableChannel chanEnd readChannel :: (ReadableChannel chanEnd) => chanEnd a -> CHP a extReadChannel :: (ReadableChannel chanEnd) => chanEnd a -> (a -> CHP b) -> CHP b -- | A class indicating that a channel can be written to. class WriteableChannel chanEnd writeChannel :: (WriteableChannel chanEnd) => chanEnd a -> a -> CHP () extWriteChannel :: (WriteableChannel chanEnd) => chanEnd a -> CHP a -> CHP () extWriteChannel' :: (WriteableChannel chanEnd) => chanEnd a -> CHP (a, b) -> CHP b -- | A useful synonym for flip writeChannel. Especially useful -- with claim so that instead of writing claim output (flip -- writeChannel 6) you can write claim output (writeValue -- 6). -- -- Added in version 1.5.0. writeValue :: (WriteableChannel chanEnd) => a -> chanEnd a -> CHP () -- | A helper function that uses the parallel strategies library (see the -- paper: "Algorithm + Strategy = Parallelism", P.W. Trinder et al, JFP -- 8(1) 1998, -- http://www.macs.hw.ac.uk/~dsg/gph/papers/html/Strategies/strategies.html) -- to make sure that the value sent down a channel is strictly evaluated -- by the sender before transmission. -- -- This is useful when you want to write worker processes that evaluate -- data and send it back to some "harvester" process. By default the -- values sent back may be unevaluated, and thus the harvester might end -- up doing the evaluation. If you use this function, the value is -- guaranteed to be completely evaluated before sending. -- -- Added in version 1.0.2. writeChannelStrict :: (NFData a, WriteableChannel chanEnd) => chanEnd a -> a -> CHP () instance WriteableChannel Chanout instance ReadableChannel Chanin -- | The module containing all the different types of channels in CHP. -- -- A communication in CHP is always synchronised: the writer must wait -- until the reader arrives to take the data. There is thus no automatic -- or underlying buffering of data. (If you want to use buffers, see the -- Control.Concurrent.CHP.Buffers module in the chp-plus package). -- -- If it helps, a channel communication can be thought of as a -- distributed binding. Imagine you have a process that creates a channel -- and then becomes the parallel composition of two sub-processes that at -- some point communicate on that channel (formatted here as two columns -- for illustration): -- --
--   do                      c <- oneToOneChannel
--                                      (<||>)
--      do p                                   do p'
--         q                                      y <- q'
--         x <- readChannel (reader c)            writeChannel (writer c) y
--         r                                      r'
--         s x                                    s'
--   
-- -- It is as if, at the point where the two processes want to communicate, -- they come together and directly bind the value from one process in the -- other: -- --
--   do                      c <- oneToOneChannel
--                                      (<||>)
--      do p                                   do p'
--         q                                      y <- q'
--         x                            <-        return y
--         r                                      r'
--         s x                                    s'
--   
-- -- The Control.Concurrent.CHP.Channels.Creation contains functions -- relating to the creation of channels. Channels are used via their ends -- -- see the Control.Concurrent.CHP.Channels.Ends module, and the -- Control.Concurrent.CHP.Channels.Communication module. -- -- Broadcast and reduce channels are available in the -- Control.Concurrent.CHP.Channels.BroadcastReduce module, which -- is not automatically re-exported here. -- -- This module was split into several smaller modules in version 1.5.0. -- Since it re-exports all the new modules, your code should not be -- affected at all. module Control.Concurrent.CHP.Channels -- | Gets the channel's identifier. Useful if you need to be able to -- identify a channel in the trace later on. getChannelIdentifier :: Chan r w a -> Unique -- | A module containing broadcast channels (one-to-many). Whereas a -- one-to-any channel features one writer sending a single value -- to one (of many) readers, a one-to-many channel features one -- writer sending the same value to many readers. So a -- one-to-any channel involves claiming the channel-end to ensure -- exclusivity, but a one-to-many channel involves enrolling on the -- channel-end (subscribing) before it can engage in communication. -- -- A communication on a one-to-many channel only takes place when the -- writer and all readers currently enrolled agree to communicate. What -- happens when the writer wants to communicate and no readers are -- enrolled was undefined in versions 1.5.1 and earlier (the writer may -- block, or may communicate happily to no-one). However, in version -- 1.6.0 onwards the semantics are clear: a writer that communicates on a -- broadcast channel with no readers involved will succeed immediately, -- communicating to no-one (i.e. the data is lost). Similarly, a read -- from a reduce channel will immediately return mempty when no -- writers are enrolled. It is possible to get into a state of livelock -- (by repeatedly performing these instant communications) in these sorts -- of situations. -- -- This module also contains reduce channels (added in version 1.1.1). -- Because in CHP channels must have the same type at both ends, we use -- the Monoid type-class. It is important to be aware that the order of -- mappends will be non-deterministic, and thus you should either use an -- mappend that is commutative or code around this restruction. -- -- For example, a common thing to do would be to use lists as the type -- for reduce channels, make each writer write a single item list (but -- more is possible), then use the list afterwards, but be aware that it -- is unordered. If it is important to have an ordered list, make each -- writer write a pair containing a (unique) index value and the real -- data, then sort by the index value and discard it. -- -- Since reduce channels were added after the initial library design, -- there is a slight complication: it is not possible to use newChannel -- (and all similar functions) with reduce channels because it is -- impossible to express the Monoid constraint for the Channel instance. -- Instead, you must use manyToOneChannel and manyToAnyChannel. module Control.Concurrent.CHP.Channels.BroadcastReduce -- | The reading end of a broadcast channel. You must enroll on it before -- you can read from it or poison it. -- -- The Eq instance was added in version 1.4.0. data BroadcastChanin a -- | The writing end of a broadcast channel. -- -- The Eq instance was added in version 1.4.0. data BroadcastChanout a type OneToManyChannel = Chan BroadcastChanin BroadcastChanout type AnyToManyChannel = Chan BroadcastChanin (Shared BroadcastChanout) oneToManyChannel :: (MonadCHP m) => m (OneToManyChannel a) anyToManyChannel :: (MonadCHP m) => m (AnyToManyChannel a) -- | Added in version 1.5.0. -- -- In versions 1.5.0-1.7.0, the broadcast and reduce channels do not -- appear correctly in the traces. oneToManyChannel' :: (MonadCHP m) => ChanOpts a -> m (OneToManyChannel a) -- | Added in version 1.5.0. -- -- In versions 1.5.0-1.7.0, the broadcast and reduce channels do not -- appear correctly in the traces. anyToManyChannel' :: (MonadCHP m) => ChanOpts a -> m (AnyToManyChannel a) -- | The reading end of a reduce channel. -- -- The Eq instance was added in version 1.4.0. data ReduceChanin a -- | The writing end of a reduce channel. You must enroll on it before you -- can read from it or poison it. -- -- The Eq instance was added in version 1.4.0. data ReduceChanout a -- | The reduce channel version of sameChannel. -- -- This function was added in version 1.4.0. sameReduceChannel :: ReduceChanin a -> ReduceChanout a -> Bool type ManyToOneChannel = Chan ReduceChanin ReduceChanout type ManyToAnyChannel = Chan (Shared ReduceChanin) ReduceChanout manyToOneChannel :: (Monoid a, MonadCHP m) => m (ManyToOneChannel a) manyToAnyChannel :: (Monoid a, MonadCHP m) => m (ManyToAnyChannel a) -- | Added in version 1.5.0. -- -- In versions 1.5.0-1.7.0, the broadcast and reduce channels do not -- appear correctly in the traces. manyToOneChannel' :: (Monoid a, MonadCHP m) => ChanOpts a -> m (ManyToOneChannel a) -- | Added in version 1.5.0. -- -- In versions 1.5.0-1.7.0, the broadcast and reduce channels do not -- appear correctly in the traces. manyToAnyChannel' :: (Monoid a, MonadCHP m) => ChanOpts a -> m (ManyToAnyChannel a) instance Eq (ReduceChanout a) instance Eq (ReduceChanin a) instance Eq (BroadcastChanout a) instance Eq (BroadcastChanin a) instance Poisonable (ReduceChanin a) instance Poisonable (Enrolled ReduceChanout a) instance ReadableChannel ReduceChanin instance WriteableChannel (Enrolled ReduceChanout) instance Enrollable ReduceChanout a instance Eq (ReduceChannel a) instance Channel BroadcastChanin (Shared BroadcastChanout) instance Channel BroadcastChanin BroadcastChanout instance Poisonable (Enrolled BroadcastChanin a) instance Poisonable (BroadcastChanout a) instance ReadableChannel (Enrolled BroadcastChanin) instance WriteableChannel BroadcastChanout instance Enrollable BroadcastChanin a instance Eq (BroadcastChannel a) -- | This module re-exports all of the functionality of the CHP library, -- except the traces mechanism available in the -- Control.Concurrent.CHP.Traces module. -- -- For an overview of the library, take a look at the CHP tutorial: -- http://www.cs.kent.ac.uk/projects/ofa/chp/tutorial.pdf -- available from the main CHP website: -- http://www.cs.kent.ac.uk/projects/ofa/chp/, or take a look at -- the CHP blog: http://chplib.wordpress.com/. -- -- You should also look at the chp-plus package, which contains a lot of -- useful further functionality built on top of CHP. module Control.Concurrent.CHP