-- 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.2.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) -- | 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 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 ForkingT m a -- | An implementation of lift for the ForkingT monad transformer. -- -- Added in version 2.2.0. liftForking :: Monad m => m a -> 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 MonadCHP m => MonadCHP (ForkingT m) instance Monad m => Monad (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. -- -- The Alternative instance was added in version 2.2.0. 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 Monad m => MonadCHP m liftCHP :: MonadCHP m => CHP a -> m a -- | 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 -- | 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 () -- | 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 -- | Acts as const liftIO_CHP. Useful only because it mirrors a -- different definition in the chp-spec library. -- -- Added in version 2.2.0. liftIO_CHP' :: String -> IO a -> CHP a -- | 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 -- | 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 -- | 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]) -- | 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 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: -- --
-- liftM Just (readChannel c) <|> (waitFor 1000000 >> return Nothing) ---- --
-- optional (readChannel c) ---- --
-- 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: -- --
-- 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 -- | 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 (</>) -- -- 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 -- | 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: -- --
-- 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) -- | 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