chp 1.8.0 → 2.0.0
raw patch · 32 files changed
+97/−2471 lines, 32 filesdep +deepseqdep +loop-whiledep −HUnitdep −QuickCheckdep −parallelPVP ok
version bump matches the API change (PVP)
Dependencies added: deepseq, loop-while
Dependencies removed: HUnit, QuickCheck, parallel
API changes (from Hackage documentation)
- Control.Concurrent.CHP.Actions: data RecvAction a
- Control.Concurrent.CHP.Actions: data SendAction a
- Control.Concurrent.CHP.Actions: instance Poisonable (RecvAction c)
- Control.Concurrent.CHP.Actions: instance Poisonable (SendAction c)
- Control.Concurrent.CHP.Actions: makeCustomRecvAction :: CHP a -> CHP () -> CHP () -> RecvAction a
- Control.Concurrent.CHP.Actions: makeCustomSendAction :: (a -> CHP ()) -> CHP () -> CHP () -> SendAction a
- Control.Concurrent.CHP.Actions: makeRecvAction :: (ReadableChannel r, Poisonable (r a)) => r a -> RecvAction a
- Control.Concurrent.CHP.Actions: makeRecvAction' :: (ReadableChannel r, Poisonable (r a)) => r a -> (a -> b) -> RecvAction b
- Control.Concurrent.CHP.Actions: makeSendAction :: (WriteableChannel w, Poisonable (w a)) => w a -> SendAction a
- Control.Concurrent.CHP.Actions: makeSendAction' :: (WriteableChannel w, Poisonable (w b)) => w b -> (a -> b) -> SendAction a
- Control.Concurrent.CHP.Actions: nullRecvAction :: a -> RecvAction a
- Control.Concurrent.CHP.Actions: nullSendAction :: SendAction a
- Control.Concurrent.CHP.Actions: recvAction :: RecvAction a -> CHP a
- Control.Concurrent.CHP.Actions: sendAction :: SendAction a -> a -> CHP ()
- Control.Concurrent.CHP.Arrow: (*&&&*) :: (Show b, Show c, Show c') => ProcessPipelineLabel b c -> ProcessPipelineLabel b c' -> ProcessPipelineLabel b (c, c')
- Control.Concurrent.CHP.Arrow: (*****) :: (Show b, Show b', Show c, Show c') => ProcessPipelineLabel b c -> ProcessPipelineLabel b' c' -> ProcessPipelineLabel (b, b') (c, c')
- Control.Concurrent.CHP.Arrow: (*<<<*) :: (Show b) => ProcessPipelineLabel b c -> ProcessPipelineLabel a b -> ProcessPipelineLabel a c
- Control.Concurrent.CHP.Arrow: (*>>>*) :: (Show b) => ProcessPipelineLabel a b -> ProcessPipelineLabel b c -> ProcessPipelineLabel a c
- Control.Concurrent.CHP.Arrow: arrLabel :: String -> (a -> b) -> ProcessPipelineLabel a b
- Control.Concurrent.CHP.Arrow: arrStrict :: (NFData b) => (a -> b) -> ProcessPipeline a b
- Control.Concurrent.CHP.Arrow: arrStrictLabel :: (NFData b) => String -> (a -> b) -> ProcessPipelineLabel a b
- Control.Concurrent.CHP.Arrow: arrowProcess :: (Chanin a -> Chanout b -> CHP ()) -> ProcessPipeline a b
- Control.Concurrent.CHP.Arrow: arrowProcessLabel :: String -> (Chanin a -> Chanout b -> CHP ()) -> ProcessPipelineLabel a b
- Control.Concurrent.CHP.Arrow: data ProcessPipeline a b
- Control.Concurrent.CHP.Arrow: data ProcessPipelineLabel a b
- Control.Concurrent.CHP.Arrow: instance Arrow ProcessPipeline
- Control.Concurrent.CHP.Arrow: instance ArrowChoice ProcessPipeline
- Control.Concurrent.CHP.Arrow: instance Category ProcessPipeline
- Control.Concurrent.CHP.Arrow: instance Functor (ProcessPipeline a)
- Control.Concurrent.CHP.Arrow: runPipeline :: ProcessPipeline a b -> Chanin a -> Chanout b -> CHP ()
- Control.Concurrent.CHP.Arrow: runPipelineLabel :: ProcessPipelineLabel a b -> Chanin a -> Chanout b -> CHP ()
- Control.Concurrent.CHP.Behaviours: alongside :: CHPBehaviour a -> CHPBehaviour b -> CHPBehaviour (a, b)
- Control.Concurrent.CHP.Behaviours: alongside_ :: CHPBehaviour a -> CHPBehaviour b -> CHPBehaviour ()
- Control.Concurrent.CHP.Behaviours: data CHPBehaviour a
- Control.Concurrent.CHP.Behaviours: endWhen :: CHP a -> CHPBehaviour (Maybe a)
- Control.Concurrent.CHP.Behaviours: instance Functor CHPBehaviour
- Control.Concurrent.CHP.Behaviours: offer :: CHPBehaviour a -> CHP a
- Control.Concurrent.CHP.Behaviours: offerAll :: [CHPBehaviour a] -> CHP [a]
- Control.Concurrent.CHP.Behaviours: once :: CHP a -> CHPBehaviour (Maybe a)
- Control.Concurrent.CHP.Behaviours: repeatedly :: CHP a -> CHPBehaviour [a]
- Control.Concurrent.CHP.Behaviours: repeatedlyRecurse :: (a -> CHP (b, a)) -> a -> CHPBehaviour [b]
- Control.Concurrent.CHP.Behaviours: repeatedlyRecurse_ :: (a -> CHP a) -> a -> CHPBehaviour ()
- Control.Concurrent.CHP.Behaviours: repeatedly_ :: CHP a -> CHPBehaviour ()
- Control.Concurrent.CHP.Behaviours: upTo :: Int -> CHP a -> CHPBehaviour [a]
- Control.Concurrent.CHP.Buffers: accumulatingInfiniteBuffer :: Chanin a -> Chanout [a] -> CHP ()
- Control.Concurrent.CHP.Buffers: fifoBuffer :: Int -> Chanin a -> Chanout a -> CHP ()
- Control.Concurrent.CHP.Buffers: infiniteBuffer :: Chanin a -> Chanout a -> CHP ()
- Control.Concurrent.CHP.Buffers: overflowingBuffer :: Int -> Chanin a -> Chanout a -> CHP ()
- Control.Concurrent.CHP.Buffers: overwritingBuffer :: Int -> Chanin a -> Chanout a -> CHP ()
- Control.Concurrent.CHP.Common: advanceTime :: (Waitable c, Ord t) => (t -> t) -> Enrolled c t -> CHP ()
- Control.Concurrent.CHP.Common: consume :: Chanin a -> CHP ()
- Control.Concurrent.CHP.Common: consumeAlongside :: Chanin a -> CHP b -> CHP b
- Control.Concurrent.CHP.Common: extId :: Chanin a -> Chanout a -> CHP ()
- Control.Concurrent.CHP.Common: filter :: (a -> Bool) -> Chanin a -> Chanout a -> CHP ()
- Control.Concurrent.CHP.Common: id :: (ReadableChannel r, Poisonable (r a), WriteableChannel w, Poisonable (w a)) => r a -> w a -> CHP ()
- Control.Concurrent.CHP.Common: join :: (a -> b -> c) -> Chanin a -> Chanin b -> Chanout c -> CHP ()
- Control.Concurrent.CHP.Common: joinList :: [Chanin a] -> Chanout [a] -> CHP ()
- Control.Concurrent.CHP.Common: map :: (a -> b) -> Chanin a -> Chanout b -> CHP ()
- Control.Concurrent.CHP.Common: map' :: (NFData b) => (a -> b) -> Chanin a -> Chanout b -> CHP ()
- Control.Concurrent.CHP.Common: merger :: [Chanin a] -> Chanout a -> CHP ()
- Control.Concurrent.CHP.Common: parDelta :: Chanin a -> [Chanout a] -> CHP ()
- Control.Concurrent.CHP.Common: prefix :: a -> Chanin a -> Chanout a -> CHP ()
- Control.Concurrent.CHP.Common: repeat :: a -> Chanout a -> CHP ()
- Control.Concurrent.CHP.Common: replicate :: Int -> a -> Chanout a -> CHP ()
- Control.Concurrent.CHP.Common: sorter :: (Ord a) => Chanin (Maybe a) -> Chanout (Maybe a) -> CHP ()
- Control.Concurrent.CHP.Common: sorter' :: (a -> a -> Bool) -> Chanin (Maybe a) -> Chanout (Maybe a) -> CHP ()
- Control.Concurrent.CHP.Common: split :: Chanin (a, b) -> Chanout a -> Chanout b -> CHP ()
- Control.Concurrent.CHP.Common: stream :: (Traversable t) => Chanin (t a) -> Chanout a -> CHP ()
- Control.Concurrent.CHP.Common: succ :: (Enum a) => Chanin a -> Chanout a -> CHP ()
- Control.Concurrent.CHP.Common: tail :: Chanin a -> Chanout a -> CHP ()
- Control.Concurrent.CHP.Common: tap :: Chanin a -> [Chanout a] -> CHP ()
- Control.Concurrent.CHP.Common: valueStore :: (ReadableChannel r, Poisonable (r a), WriteableChannel w, Poisonable (w a)) => a -> r a -> w a -> CHP ()
- Control.Concurrent.CHP.Common: valueStore' :: (ReadableChannel r, Poisonable (r a), WriteableChannel w, Poisonable (w a)) => r a -> w a -> CHP ()
- Control.Concurrent.CHP.Connect: (<=>) :: (Connectable l r) => (a -> l -> CHP ()) -> (r -> b -> CHP ()) -> a -> b -> CHP ()
- Control.Concurrent.CHP.Connect: (<=>|) :: (Connectable l r) => (a -> l -> CHP ()) -> (r -> CHP ()) -> a -> CHP ()
- Control.Concurrent.CHP.Connect: (|<=>) :: (Connectable l r) => (l -> CHP ()) -> (r -> b -> CHP ()) -> b -> CHP ()
- Control.Concurrent.CHP.Connect: (|<=>|) :: (Connectable l r) => (l -> CHP ()) -> (r -> CHP ()) -> CHP ()
- Control.Concurrent.CHP.Connect: class Connectable l r
- Control.Concurrent.CHP.Connect: class ConnectableExtra l r where { type family ConnectableParam l; }
- Control.Concurrent.CHP.Connect: connect :: (Connectable l r) => ((l, r) -> CHP a) -> CHP a
- Control.Concurrent.CHP.Connect: connectExtra :: (ConnectableExtra l r) => ConnectableParam l -> ((l, r) -> CHP ()) -> CHP ()
- Control.Concurrent.CHP.Connect: connectList :: (Connectable l r) => Int -> ([(l, r)] -> CHP a) -> CHP a
- Control.Concurrent.CHP.Connect: connectList_ :: (Connectable l r) => Int -> ([(l, r)] -> CHP a) -> CHP ()
- Control.Concurrent.CHP.Connect: connectWith :: (ConnectableExtra l r) => ConnectableParam l -> (a -> l -> CHP ()) -> (r -> b -> CHP ()) -> a -> b -> CHP ()
- Control.Concurrent.CHP.Connect: cycleConnect :: (Connectable l r) => [r -> l -> CHP ()] -> CHP ()
- Control.Concurrent.CHP.Connect: data ChannelPair l r
- Control.Concurrent.CHP.Connect: instance (Connectable al ar, Connectable bl br) => Connectable (al, bl) (ar, br)
- Control.Concurrent.CHP.Connect: instance (Connectable al ar, Connectable bl br, Connectable cl cr) => Connectable (al, bl, cl) (ar, br, cr)
- Control.Concurrent.CHP.Connect: instance (Connectable al ar, Connectable bl br, Connectable cl cr, Connectable dl dr) => Connectable (al, bl, cl, dl) (ar, br, cr, dr)
- Control.Concurrent.CHP.Connect: instance (Connectable al ar, Connectable bl br, Connectable cl cr, Connectable dl dr, Connectable el er) => Connectable (al, bl, cl, dl, el) (ar, br, cr, dr, er)
- Control.Concurrent.CHP.Connect: instance (Connectable l r) => Connectable (ChannelPair l r) (ChannelPair l r)
- Control.Concurrent.CHP.Connect: instance (ConnectableExtra al ar, ConnectableExtra bl br) => ConnectableExtra (al, bl) (ar, br)
- Control.Concurrent.CHP.Connect: instance (ConnectableExtra al ar, ConnectableExtra bl br, ConnectableExtra cl cr) => ConnectableExtra (al, bl, cl) (ar, br, cr)
- Control.Concurrent.CHP.Connect: instance (ConnectableExtra al ar, ConnectableExtra bl br, ConnectableExtra cl cr, ConnectableExtra dl dr) => ConnectableExtra (al, bl, cl, dl) (ar, br, cr, dr)
- Control.Concurrent.CHP.Connect: instance (ConnectableExtra al ar, ConnectableExtra bl br, ConnectableExtra cl cr, ConnectableExtra dl dr, ConnectableExtra el er) => ConnectableExtra (al, bl, cl, dl, el) (ar, br, cr, dr, er)
- Control.Concurrent.CHP.Connect: instance (Eq l, Eq r) => Eq (ChannelPair l r)
- Control.Concurrent.CHP.Connect: instance (Show l, Show r) => Show (ChannelPair l r)
- Control.Concurrent.CHP.Connect: instance Connectable (Chanin a) (Chanout a)
- Control.Concurrent.CHP.Connect: instance Connectable (Chanout a) (Chanin a)
- Control.Concurrent.CHP.Connect: instance Connectable (Enrolled PhasedBarrier ()) (Enrolled PhasedBarrier ())
- Control.Concurrent.CHP.Connect: instance ConnectableExtra (Chanin a) (Chanout a)
- Control.Concurrent.CHP.Connect: instance ConnectableExtra (Chanout a) (Chanin a)
- Control.Concurrent.CHP.Connect: instance ConnectableExtra (Enrolled PhasedBarrier ph) (Enrolled PhasedBarrier ph)
- Control.Concurrent.CHP.Connect: pipelineConnect :: (Connectable l r) => [r -> l -> CHP ()] -> r -> l -> CHP ()
- Control.Concurrent.CHP.Connect: pipelineConnectComplete :: (Connectable l r) => (l -> CHP ()) -> [r -> l -> CHP ()] -> (r -> CHP ()) -> CHP ()
- Control.Concurrent.CHP.Connect: pipelineConnectCompleteT :: (Connectable l r) => ([a] -> CHP b) -> (l -> a) -> [r -> l -> a] -> (r -> a) -> CHP b
- Control.Concurrent.CHP.Connect.TwoDim: FourWay :: above -> below -> left -> right -> FourWay above below left right
- Control.Concurrent.CHP.Connect.TwoDim: FourWayDiag :: aboveLeft -> belowRight -> aboveRight -> belowLeft -> FourWayDiag aboveLeft belowRight aboveRight belowLeft
- Control.Concurrent.CHP.Connect.TwoDim: above :: FourWay above below left right -> above
- Control.Concurrent.CHP.Connect.TwoDim: aboveLeft :: FourWayDiag aboveLeft belowRight aboveRight belowLeft -> aboveLeft
- Control.Concurrent.CHP.Connect.TwoDim: aboveRight :: FourWayDiag aboveLeft belowRight aboveRight belowLeft -> aboveRight
- Control.Concurrent.CHP.Connect.TwoDim: below :: FourWay above below left right -> below
- Control.Concurrent.CHP.Connect.TwoDim: belowLeft :: FourWayDiag aboveLeft belowRight aboveRight belowLeft -> belowLeft
- Control.Concurrent.CHP.Connect.TwoDim: belowRight :: FourWayDiag aboveLeft belowRight aboveRight belowLeft -> belowRight
- Control.Concurrent.CHP.Connect.TwoDim: data FourWay above below left right
- Control.Concurrent.CHP.Connect.TwoDim: data FourWayDiag aboveLeft belowRight aboveRight belowLeft
- Control.Concurrent.CHP.Connect.TwoDim: instance (Eq above, Eq below, Eq left, Eq right) => Eq (FourWay above below left right)
- Control.Concurrent.CHP.Connect.TwoDim: instance (Eq aboveLeft, Eq belowRight, Eq aboveRight, Eq belowLeft) => Eq (FourWayDiag aboveLeft belowRight aboveRight belowLeft)
- Control.Concurrent.CHP.Connect.TwoDim: left :: FourWay above below left right -> left
- Control.Concurrent.CHP.Connect.TwoDim: right :: FourWay above below left right -> right
- Control.Concurrent.CHP.Connect.TwoDim: type EightWay a b l r al br ar bl = (FourWay a b l r, FourWayDiag al br ar bl)
- Control.Concurrent.CHP.Connect.TwoDim: wrappedGridEight :: (Connectable above below, Connectable left right, Connectable aboveLeft belowRight, Connectable belowLeft aboveRight) => [[EightWay above below left right aboveLeft belowRight aboveRight belowLeft -> CHP a]] -> CHP [[a]]
- Control.Concurrent.CHP.Connect.TwoDim: wrappedGridEight_ :: (Connectable above below, Connectable left right, Connectable aboveLeft belowRight, Connectable belowLeft aboveRight) => [[EightWay above below left right aboveLeft belowRight aboveRight belowLeft -> CHP a]] -> CHP ()
- Control.Concurrent.CHP.Connect.TwoDim: wrappedGridFour :: (Connectable above below, Connectable left right) => [[FourWay above below left right -> CHP a]] -> CHP [[a]]
- Control.Concurrent.CHP.Connect.TwoDim: wrappedGridFour_ :: (Connectable above below, Connectable left right) => [[FourWay above below left right -> CHP a]] -> CHP ()
- Control.Concurrent.CHP.Console: ConsoleChans :: Chanin Char -> Chanout Char -> Chanout Char -> ConsoleChans
- Control.Concurrent.CHP.Console: cStderr :: ConsoleChans -> Chanout Char
- Control.Concurrent.CHP.Console: cStdin :: ConsoleChans -> Chanin Char
- Control.Concurrent.CHP.Console: cStdout :: ConsoleChans -> Chanout Char
- Control.Concurrent.CHP.Console: consoleProcess :: (ConsoleChans -> CHP ()) -> CHP ()
- Control.Concurrent.CHP.Console: data ConsoleChans
- Control.Concurrent.CHP.Monad: data (Monad m) => LoopWhileT m a
- Control.Concurrent.CHP.Monad: instance (Monad m) => Monad (LoopWhileT m)
- Control.Concurrent.CHP.Monad: instance (MonadCHP m) => MonadCHP (LoopWhileT m)
- Control.Concurrent.CHP.Monad: instance (MonadIO m) => MonadIO (LoopWhileT m)
- Control.Concurrent.CHP.Monad: instance MonadTrans LoopWhileT
- Control.Concurrent.CHP.Monad: loop :: (Monad m) => LoopWhileT m a -> m ()
- Control.Concurrent.CHP.Monad: while :: (Monad m) => Bool -> LoopWhileT m ()
- Control.Concurrent.CHP.Test: (=*=) :: (Eq a, Show a) => a -> a -> CHPTestResult
- Control.Concurrent.CHP.Test: CHPTestFail :: String -> CHPTestResult
- Control.Concurrent.CHP.Test: CHPTestPass :: CHPTestResult
- Control.Concurrent.CHP.Test: assertCHP :: CHP () -> String -> Bool -> CHPTest ()
- Control.Concurrent.CHP.Test: assertCHP' :: String -> Bool -> CHPTest ()
- Control.Concurrent.CHP.Test: assertCHPEqual :: (Eq a, Show a) => CHP () -> String -> a -> a -> CHPTest ()
- Control.Concurrent.CHP.Test: assertCHPEqual' :: (Eq a, Show a) => String -> a -> a -> CHPTest ()
- Control.Concurrent.CHP.Test: data CHPTest a
- Control.Concurrent.CHP.Test: data CHPTestResult
- Control.Concurrent.CHP.Test: data QuickCheckCHP a
- Control.Concurrent.CHP.Test: instance Monad CHPTest
- Control.Concurrent.CHP.Test: instance MonadCHP CHPTest
- Control.Concurrent.CHP.Test: instance MonadIO CHPTest
- Control.Concurrent.CHP.Test: instance Monoid CHPTestResult
- Control.Concurrent.CHP.Test: instance Testable (QuickCheckCHP Bool)
- Control.Concurrent.CHP.Test: instance Testable (QuickCheckCHP CHPTestResult)
- Control.Concurrent.CHP.Test: instance Testable (QuickCheckCHP Result)
- Control.Concurrent.CHP.Test: propCHPInOut :: (Show a) => (a -> b -> Bool) -> (Chanin a -> Chanout b -> CHP ()) -> Gen a -> Property
- Control.Concurrent.CHP.Test: qcCHP :: CHP a -> QuickCheckCHP a
- Control.Concurrent.CHP.Test: qcCHP' :: (Trace t) => IO (Maybe a, t Unique) -> QuickCheckCHP a
- Control.Concurrent.CHP.Test: testCHP :: CHP Bool -> Test
- Control.Concurrent.CHP.Test: testCHP' :: CHP CHPTestResult -> Test
- Control.Concurrent.CHP.Test: testCHPInOut :: (a -> b -> Bool) -> (Chanin a -> Chanout b -> CHP ()) -> a -> Test
- Control.Concurrent.CHP.Test: withCheck :: CHP a -> CHPTest () -> CHP CHPTestResult
- Control.Concurrent.CHP.Utils: (->|) :: (Chanout b -> CHP ()) -> (Chanin b -> c -> CHP ()) -> (c -> CHP ())
- Control.Concurrent.CHP.Utils: (<->|) :: ((Chanin b, Chanout c) -> CHP ()) -> ((Chanin c, Chanout b) -> a -> CHP ()) -> (a -> CHP ())
- Control.Concurrent.CHP.Utils: (|->) :: (a -> Chanout b -> CHP ()) -> (Chanin b -> CHP ()) -> (a -> CHP ())
- Control.Concurrent.CHP.Utils: (|->|) :: (a -> Chanout b -> CHP ()) -> (Chanin b -> c -> CHP ()) -> (a -> c -> CHP ())
- Control.Concurrent.CHP.Utils: (|->|^) :: (Show b) => (a -> Chanout b -> CHP ()) -> (String, Chanin b -> c -> CHP ()) -> (a -> c -> CHP ())
- Control.Concurrent.CHP.Utils: (|<->) :: (a -> (Chanin b, Chanout c) -> CHP ()) -> ((Chanin c, Chanout b) -> CHP ()) -> (a -> CHP ())
- Control.Concurrent.CHP.Utils: (|<->|) :: (a -> (Chanin b, Chanout c) -> CHP ()) -> ((Chanin c, Chanout b) -> d -> CHP ()) -> (a -> d -> CHP ())
- Control.Concurrent.CHP.Utils: (|<-|) :: (Chanin b -> c -> CHP ()) -> (a -> Chanout b -> CHP ()) -> (a -> c -> CHP ())
- Control.Concurrent.CHP.Utils: cycle :: [Chanin a -> Chanout a -> CHP b] -> CHP [b]
- Control.Concurrent.CHP.Utils: dualCycle :: [(Chanin a, Chanout b) -> (Chanin b, Chanout a) -> CHP c] -> CHP [c]
- Control.Concurrent.CHP.Utils: dualPipeline :: [(Chanin a, Chanout b) -> (Chanin b, Chanout a) -> CHP c] -> (Chanin a, Chanout b) -> (Chanin b, Chanout a) -> CHP [c]
- Control.Concurrent.CHP.Utils: pipeline :: [Chanin a -> Chanout a -> CHP b] -> Chanin a -> Chanout a -> CHP [b]
- Control.Concurrent.CHP.Utils: wireCycle :: (Channel r w) => [r a -> w a -> proc] -> CHP [proc]
- Control.Concurrent.CHP.Utils: wireDualCycle :: (Channel r w, Channel r' w') => [(r a, w' b) -> (r' b, w a) -> proc] -> CHP [proc]
- Control.Concurrent.CHP.Utils: wireDualPipeline :: (Channel r w, Channel r' w') => [(r a, w' b) -> (r' b, w a) -> proc] -> (r a, w' b) -> (r' b, w a) -> CHP [proc]
- Control.Concurrent.CHP.Utils: wirePipeline :: (Channel r w) => [r a -> w a -> proc] -> r a -> w a -> CHP [proc]
Files
- Control/Concurrent/CHP.hs +7/−24
- Control/Concurrent/CHP/Actions.hs +0/−122
- Control/Concurrent/CHP/Alt.hs +5/−4
- Control/Concurrent/CHP/Arrow.hs +0/−334
- Control/Concurrent/CHP/Base.hs +14/−7
- Control/Concurrent/CHP/Behaviours.hs +0/−204
- Control/Concurrent/CHP/BroadcastChannels.hs +0/−35
- Control/Concurrent/CHP/Buffers.hs +0/−145
- Control/Concurrent/CHP/CSP.hs +5/−5
- Control/Concurrent/CHP/Channels.hs +2/−2
- Control/Concurrent/CHP/Channels/Base.hs +1/−2
- Control/Concurrent/CHP/Channels/BroadcastReduce.hs +6/−8
- Control/Concurrent/CHP/Channels/Communication.hs +4/−3
- Control/Concurrent/CHP/Clocks.hs +8/−8
- Control/Concurrent/CHP/Common.hs +0/−307
- Control/Concurrent/CHP/Connect.hs +0/−232
- Control/Concurrent/CHP/Connect/TwoDim.hs +0/−231
- Control/Concurrent/CHP/Console.hs +0/−114
- Control/Concurrent/CHP/Enroll.hs +1/−1
- Control/Concurrent/CHP/Event.hs +18/−9
- Control/Concurrent/CHP/Guard.hs +3/−3
- Control/Concurrent/CHP/Monad.hs +0/−45
- Control/Concurrent/CHP/Mutex.hs +1/−1
- Control/Concurrent/CHP/Parallel.hs +1/−1
- Control/Concurrent/CHP/Test.hs +0/−325
- Control/Concurrent/CHP/Traces.hs +2/−2
- Control/Concurrent/CHP/Traces/Base.hs +6/−7
- Control/Concurrent/CHP/Traces/CSP.hs +2/−2
- Control/Concurrent/CHP/Traces/Structural.hs +1/−1
- Control/Concurrent/CHP/Traces/VCR.hs +1/−1
- Control/Concurrent/CHP/Utils.hs +0/−267
- chp.cabal +9/−19
Control/Concurrent/CHP.hs view
@@ -27,38 +27,21 @@ -- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --- | This module re-exports the core functionality of the CHP library. Other--- modules that you also may wish to import are:------ * "Control.Concurrent.CHP.Actions"--- --- * "Control.Concurrent.CHP.Arrow"--- --- * "Control.Concurrent.CHP.Behaviours"------ * "Control.Concurrent.CHP.Buffers"------ * "Control.Concurrent.CHP.Common"------ * "Control.Concurrent.CHP.Connect"--- --- * "Control.Concurrent.CHP.Console"------ * "Control.Concurrent.CHP.Test"------ * "Control.Concurrent.CHP.Traces"------ * "Control.Concurrent.CHP.Utils"+-- | 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 ( module Control.Concurrent.CHP.Alt, module Control.Concurrent.CHP.Barriers,- module Control.Concurrent.CHP.BroadcastChannels, module Control.Concurrent.CHP.Channels,+ module Control.Concurrent.CHP.Channels.BroadcastReduce, module Control.Concurrent.CHP.Clocks, module Control.Concurrent.CHP.Enroll, module Control.Concurrent.CHP.Monad,@@ -67,8 +50,8 @@ import Control.Concurrent.CHP.Alt import Control.Concurrent.CHP.Barriers-import Control.Concurrent.CHP.BroadcastChannels import Control.Concurrent.CHP.Channels+import Control.Concurrent.CHP.Channels.BroadcastReduce import Control.Concurrent.CHP.Clocks import Control.Concurrent.CHP.Enroll import Control.Concurrent.CHP.Monad
− Control/Concurrent/CHP/Actions.hs
@@ -1,122 +0,0 @@--- Communicating Haskell Processes.--- Copyright (c) 2009, University of Kent.--- All rights reserved.--- --- Redistribution and use in source and binary forms, with or without--- modification, are permitted provided that the following conditions are--- met:------ * Redistributions of source code must retain the above copyright--- notice, this list of conditions and the following disclaimer.--- * Redistributions in binary form must reproduce the above copyright--- notice, this list of conditions and the following disclaimer in the--- documentation and/or other materials provided with the distribution.--- * Neither the name of the University of Kent nor the names of its--- contributors may be used to endorse or promote products derived from--- this software without specific prior written permission.------ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS--- IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,--- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR--- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR--- CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,--- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,--- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR--- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF--- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING--- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS--- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.---- | A module containing action wrappers around channel-ends.------ In CHP, there are a variety of channel-ends. Enrolled Chanin, Shared Chanout,--- plain Chanin, and so on. The difference between these ends can be important;--- enrolled channel-ends can be resigned from, shared channel-ends need to be claimed--- before use. But sometimes you just want to ignore those differences and read--- and write from the channel-end regardless of its type. In particular, you want--- to pass a channel-end to a process without the process worrying about its type.------ Actions allow you to do this. A send action is like a monadic function (@a--- -> CHP()@ for sending an item, but can be poisoned too. A recv action is like--- something of type @CHP a@ that again can be poisoned.-module Control.Concurrent.CHP.Actions- ( SendAction, RecvAction,- sendAction, recvAction,- makeSendAction, makeRecvAction,- makeSendAction', makeRecvAction',- makeCustomSendAction, makeCustomRecvAction,- nullSendAction, nullRecvAction- ) where--import Control.Concurrent.CHP-import Control.Monad---- | A send action. See 'sendAction'. Note that it is poisonable.-newtype SendAction a = SendAction (a -> CHP (), CHP (), CHP ())--- | A receive action. See 'recvAction'. Note that it is poisonable.-newtype RecvAction a = RecvAction (CHP a, CHP (), CHP ())---- | Sends a data item using the given sendAction. Whether this operation can--- be used in a choice (see 'alt') is entirely dependent on whether the original--- action could be used in an alt. For all of CHP's channels, this is true, but--- for your own custom send actions, probably not.-sendAction :: SendAction a -> a -> CHP ()-sendAction (SendAction (s, _, _)) = s---- | Receives a data item using the given recvAction. Whether this operation can--- be used in a choice (see 'alt') is entirely dependent on whether the original--- action could be used in an alt. For all of CHP's channels, this is true, but--- for your own custom receive actions, probably not.-recvAction :: RecvAction a -> CHP a-recvAction (RecvAction (s, _, _)) = s--instance Poisonable (SendAction c) where- poison (SendAction (_,p,_)) = liftCHP p- checkForPoison (SendAction (_,_,c)) = liftCHP c--instance Poisonable (RecvAction c) where- poison (RecvAction (_,p,_)) = liftCHP p- checkForPoison (RecvAction (_,_,c)) = liftCHP c---- | Given a writing channel end, gives back the corresponding 'SendAction'.-makeSendAction :: (WriteableChannel w, Poisonable (w a)) => w a -> SendAction a-makeSendAction c = SendAction (writeChannel c, poison c, checkForPoison c)---- | Like 'makeSendAction', but always applies the given function before sending--- the item.-makeSendAction' :: (WriteableChannel w, Poisonable (w b)) =>- w b -> (a -> b) -> SendAction a-makeSendAction' c f = SendAction (writeChannel c . f, poison c, checkForPoison c)---- | Given a reading channel end, gives back the corresponding 'RecvAction'.-makeRecvAction :: (ReadableChannel r, Poisonable (r a)) => r a -> RecvAction a-makeRecvAction c = RecvAction (readChannel c, poison c, checkForPoison c)---- | Like 'makeRecvAction', but always applies the given function after receiving--- an item.-makeRecvAction' :: (ReadableChannel r, Poisonable (r a)) =>- r a -> (a -> b) -> RecvAction b-makeRecvAction' c f = RecvAction (liftM f $ readChannel c, poison c, checkForPoison c)---- | Creates a custom send operation. The first parameter should perform the send,--- the second parameter should poison your communication channel, and the third--- parameter should check whether the communication channel is already poisoned.--- Generally, you will want to use 'makeSendAction' instead of this function.-makeCustomSendAction :: (a -> CHP ()) -> CHP () -> CHP () -> SendAction a-makeCustomSendAction x y z = SendAction (x, y, z)---- | Creates a custom receive operation. The first parameter should perform the receive,--- the second parameter should poison your communication channel, and the third--- parameter should check whether the communication channel is already poisoned.--- Generally, you will want to use 'makeRecvAction' instead of this function.-makeCustomRecvAction :: CHP a -> CHP () -> CHP () -> RecvAction a-makeCustomRecvAction x y z = RecvAction (x, y, z)---- | Acts like a SendAction, but just discards the data.-nullSendAction :: SendAction a-nullSendAction = SendAction (const $ return (), return (), return ())---- | Acts like a RecvAction, but always gives back the given data item.-nullRecvAction :: a -> RecvAction a-nullRecvAction x = RecvAction (return x, return (), return ())-
Control/Concurrent/CHP/Alt.hs view
@@ -103,6 +103,7 @@ -- would). module Control.Concurrent.CHP.Alt (alt, (<->), priAlt, (</>), every, every_, (<&>)) where +import Control.Applicative import Control.Arrow import Control.Concurrent.STM import Control.Monad.Reader@@ -173,7 +174,7 @@ -- Whichever channel is chosen by both processes will not satisfy the priority -- at one end (if such priority between channels was supported). priAlt :: [CHP a] -> CHP a-priAlt items = unwrapPoison $ priAlt' $ map wrapPoison items+priAlt = unwrapPoison . priAlt' . map wrapPoison -- | A useful operator to perform an 'alt'. This operator is associative, -- and has arbitrary priority. When you have lots of guards, it is probably easier@@ -331,7 +332,7 @@ -- -- Added in version 1.1.0 (<&>) :: forall a b. CHP a -> CHP b -> CHP (a, b)-(<&>) a b = every [a >>= return . Left, b >>= return . Right] >>= return . merge+(<&>) a b = merge <$> every [Left <$> a, Right <$> b] where merge :: [Either a b] -> (a, b) merge [Left x, Right y] = (x, y)@@ -396,8 +397,8 @@ getRec (Signal PoisonItem, _) = PoisonItem getRec (Signal (NoPoison n), m) = case both !! n of- (EventGuard rec _ _, body) ->- NoPoison (rec (makeLookup m), body)+ (EventGuard recF _ _, body) ->+ NoPoison (recF (makeLookup m), body) (_, body) -> NoPoison ([], body) tv <- liftIO $ newTVarIO Nothing pid <- getProcessId
− Control/Concurrent/CHP/Arrow.hs
@@ -1,334 +0,0 @@--- Communicating Haskell Processes.--- Copyright (c) 2008, University of Kent.--- All rights reserved.--- --- Redistribution and use in source and binary forms, with or without--- modification, are permitted provided that the following conditions are--- met:------ * Redistributions of source code must retain the above copyright--- notice, this list of conditions and the following disclaimer.--- * Redistributions in binary form must reproduce the above copyright--- notice, this list of conditions and the following disclaimer in the--- documentation and/or other materials provided with the distribution.--- * Neither the name of the University of Kent nor the names of its--- contributors may be used to endorse or promote products derived from--- this software without specific prior written permission.------ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS--- IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,--- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR--- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR--- CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,--- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,--- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR--- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF--- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING--- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS--- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.----- | Provides an instance of Arrow for process pipelines. As described in--- the original paper on arrows, they can be used to represent stream processing,--- so CHP seemed like a possible fit for an arrow.--- --- Whether this is /actually/ an instance of Arrow depends on technicalities.--- This can be demonstrated with the arrow law @arr id >>> f = f = f >>> arr--- id@. Whether CHP satisfies this arrow law depends on the definition of--- equality.------ * If equality means that given the same input value, both arrows produce the--- same corresponding output value, this is an arrow.------ * If equality means you give the arrows the same single input and wait for the single output,--- and the output is the same, this is an arrow.------ * If equality means that you can feed the arrows lots of inputs (one after--- the other) and the behaviour should be the same with regards to communication,--- this is not an arrow.------ The problem lies in the buffering inherent in arrows. Imagine if @f@ is--- a single function. @f@ is effectively a buffer of one. You can feed it--- a single value, but no more than that until you read its output. However,--- if you have @arr id >>> f@, that can accept two inputs (one held by the--- @arr id@ process and one held by @f@) before you must accept the output.------ I am fairly confident that the arrow laws are satisfied for the--- definition of equality that given the same single input, they will--- produce the same single output. If you don't worry too much about the--- behavioural difference, and just take arrows as another way to wire--- together a certain class of process network, you should do fine.------ Added in version 1.0.2.-module Control.Concurrent.CHP.Arrow (ProcessPipeline, runPipeline, arrowProcess, arrStrict,- ProcessPipelineLabel, runPipelineLabel, arrowProcessLabel, arrLabel, arrStrictLabel,- (*>>>*), (*<<<*), (*&&&*), (*****)) where---- I have got this module to work on GHC 6.8 and 6.10 by following the CPP-variant--- instructions on this page: http://haskell.org/haskellwiki/Upgrading_packages--#if __GLASGOW_HASKELL__ >= 609-import Control.Category-import Prelude hiding ((.), id)-#endif--import Control.Arrow-#if __GLASGOW_HASKELL__ < 610- hiding (pure)-#endif-import Control.Monad-import Control.Parallel.Strategies--import Control.Concurrent.CHP-import qualified Control.Concurrent.CHP.Common as CHP-import Control.Concurrent.CHP.Utils---- | ProcessPipelineLabel is a version of 'ProcessPipeline' that allows the processes--- to be labelled, and thus in turn for the channels connecting the processes to--- be automatically labelled. ProcessPipelineLabel is not an instance of Arrow,--- but it does have a lot of similarly named functions for working with it. This--- awkwardness is due to the extra Show constraints on the connectors that allow--- the arrow's contents to appear in traces.------ If you don't use traces, use 'ProcessPipeline'. If you do use traces, and want--- to have better labels on the process and values used in your arrows, consider--- switching to ProcessPipelineLabel.------ ProcessPipelineLabel and all the functions that use it, were added in version--- 1.5.0.-data ProcessPipelineLabel a b = ProcessPipelineLabel- { runPipelineLabel :: Chanin a -> Chanout b -> CHP ()- -- ^ Like 'runPipeline' but for 'ProcessPipelineLabel'- , _pipelineLabels :: (String, String)- }---- | Like 'arrowProcess', but allows the process to be labelled. The same--- warnings as 'arrowProcess' apply.-arrowProcessLabel :: String -> (Chanin a -> Chanout b -> CHP ()) -> ProcessPipelineLabel a b-arrowProcessLabel l p = ProcessPipelineLabel p (l, l)---- | Like 'arr' for 'ProcessPipeline', but allows the process to be labelled.-arrLabel :: String -> (a -> b) -> ProcessPipelineLabel a b-arrLabel l = arrowProcessLabel l . CHP.map---- | Like 'arrStrict', but allows the process to be labelled.-arrStrictLabel :: NFData b => String -> (a -> b) -> ProcessPipelineLabel a b-arrStrictLabel l = arrowProcessLabel l . CHP.map'---- | The '(>>>)' arrow combinator, for 'ProcessPipelineLabel'.-(*>>>*) :: Show b => ProcessPipelineLabel a b -> ProcessPipelineLabel b c- -> ProcessPipelineLabel a c-(*>>>*) (ProcessPipelineLabel p (pl, pr)) (ProcessPipelineLabel q (ql, qr))- = ProcessPipelineLabel (p |->|^ (pr ++ "->" ++ ql, q)) (pl, qr)---- | The '(<<<)' arrow combinator, for 'ProcessPipelineLabel'.-(*<<<*) :: Show b => ProcessPipelineLabel b c -> ProcessPipelineLabel a b- -> ProcessPipelineLabel a c-(*<<<*) = flip (*>>>*)---- | The '(&&&)' arrow combinator, for 'ProcessPipelineLabel'.-(*&&&*) :: (Show b, Show c, Show c') => ProcessPipelineLabel b c -> ProcessPipelineLabel b c' -> ProcessPipelineLabel b (c, c')-(*&&&*) (ProcessPipelineLabel p (pl, pr))- (ProcessPipelineLabel q (ql, qr))- = ProcessPipelineLabel proc (mix pl ql, mix pr qr)- where- mix a b = "(" ++ a ++ "*&&&*" ++ b ++ ")"- proc input output- = do deltaP <- oneToOneChannel' $ chanLabel $ pl ++ ".in"- deltaQ <- oneToOneChannel' $ chanLabel $ ql ++ ".in"- joinP <- oneToOneChannel' $ chanLabel $ pr ++ ".out"- joinQ <- oneToOneChannel' $ chanLabel $ qr ++ ".out"- runParallel_- [CHP.parDelta input (writers [deltaP, deltaQ])- ,p (reader deltaP) (writer joinP)- ,q (reader deltaQ) (writer joinQ)- ,CHP.join (,) (reader joinP) (reader joinQ) output- ]---- | The '(***)' arrow combinator, for 'ProcessPipelineLabel'.-(*****) :: (Show b, Show b', Show c, Show c') => ProcessPipelineLabel b c -> ProcessPipelineLabel b' c'- -> ProcessPipelineLabel (b, b') (c, c')-(*****) (ProcessPipelineLabel p (pl, pr))- (ProcessPipelineLabel q (ql, qr))- = ProcessPipelineLabel proc (mix pl ql, mix pr qr)- where- mix a b = "(" ++ a ++ "*****" ++ b ++ ")"- proc input output- = do deltaP <- oneToOneChannel' $ chanLabel $ mix pl ql ++ "->" ++ pl- deltaQ <- oneToOneChannel' $ chanLabel $ mix pl ql ++ "->" ++ ql- joinP <- oneToOneChannel' $ chanLabel $ pr ++ "->" ++ mix pr qr- joinQ <- oneToOneChannel' $ chanLabel $ qr ++ "->" ++ mix pr qr- runParallel_- [CHP.split input (writer deltaP) (writer deltaQ)- ,p (reader deltaP) (writer joinP)- ,q (reader deltaQ) (writer joinQ)- ,CHP.join (,) (reader joinP) (reader joinQ) output- ]----- | The type that is an instance of 'Arrow' for process pipelines. See 'runPipeline'.------ The 'Functor' instance was added in version 1.6.0.-data ProcessPipeline a b = ProcessPipeline- { runPipeline :: Chanin a -> Chanout b -> CHP ()- -- ^ Given a 'ProcessPipeline' (formed using its 'Arrow' instance) and- -- the channels to plug into the ends of the pipeline, returns the process- -- representing the pipeline.- --- -- The pipeline will run forever (until poisoned) and you must run it in- -- parallel to whatever is feeding it the inputs and reading off the outputs.- -- Imagine that you want a process pipeline that takes in a pair of numbers,- -- doubles the first and adds one to the second. You could encode this- -- in an arrow using:- -- - -- > runPipeline (arr (*2) *** arr (+1))- --- -- Arrows are more useful where you already have processes written that- -- process data and you want to easily wire them together. The arrow notation- -- is probably easier for doing that than declaring all the channels yourself- -- and composing everything in parallel.- }---- | Adds a wrapper that forms this process into the right data type to be--- part of an arrow.------ Any process you apply this to should produce exactly one output per--- input, or else you will find odd behaviour resulting (including deadlock).--- So for example, /don't/ use @arrowProcess ('Control.Concurrent.CHP.Common.filter'--- ...)@ or @arrowProcess 'Control.Concurrent.CHP.Common.stream'@ inside any arrow combinators--- other than >>> and <<<.------ Added in version 1.1.0-arrowProcess :: (Chanin a -> Chanout b -> CHP ()) -> ProcessPipeline a b-arrowProcess = ProcessPipeline---- | Like the arr function of the ProcessPipeline arrow instance, but fully evaluates--- the result before sending it. If you are building process pipelines with arrows to--- try and get some parallel speed-up, you should try this function instead of--- arr itself.--- --- Added in version 1.3.2-arrStrict :: NFData b => (a -> b) -> ProcessPipeline a b-arrStrict = ProcessPipeline . CHP.map'--instance Functor (ProcessPipeline a) where- fmap f x = x >>> arr f--#if __GLASGOW_HASKELL__ >= 609-instance Category ProcessPipeline where- (ProcessPipeline q) . (ProcessPipeline p) = ProcessPipeline (p |->| q)- id = ProcessPipeline CHP.id-#endif--instance Arrow ProcessPipeline where-#if __GLASGOW_HASKELL__ < 609- (ProcessPipeline p) >>> (ProcessPipeline q) = ProcessPipeline (p |->| q)-#endif- arr = ProcessPipeline . CHP.map-- first (ProcessPipeline p) = ProcessPipeline $ \in_ out -> do- c <- newChannel- c' <- newChannel- d <- newChannel- runParallel_- [ CHP.split in_ (writer c) (writer d)- , p (reader c) (writer c')- , CHP.join (,) (reader c') (reader d) out- ]-- second (ProcessPipeline p) = ProcessPipeline $ \in_ out -> do- c <- newChannel- c' <- newChannel- d <- newChannel- runParallel_- [ CHP.split in_ (writer d) (writer c)- , p (reader c) (writer c')- , CHP.join (,) (reader d) (reader c') out- ]-- (ProcessPipeline p) *** (ProcessPipeline q) = ProcessPipeline $ \in_ out -> do- c <- newChannel- c' <- newChannel- d <- newChannel- d' <- newChannel- runParallel_- [ CHP.split in_ (writer c) (writer d)- , p (reader c) (writer c')- , q (reader d) (writer d')- , CHP.join (,) (reader c') (reader d') out- ]-- (ProcessPipeline p) &&& (ProcessPipeline q) = ProcessPipeline $ \in_ out -> do- c <- newChannel- c' <- newChannel- d <- newChannel- d' <- newChannel- runParallel_- [ CHP.parDelta in_ [writer c, writer d]- , p (reader c) (writer c')- , q (reader d) (writer d')- , CHP.join (,) (reader c') (reader d') out- ]--instance ArrowChoice ProcessPipeline where- left (ProcessPipeline p) = ProcessPipeline $ \in_ out -> do- c <- oneToOneChannel- d <- oneToOneChannel- (forever $ do x <- readChannel in_- case x of- Left l -> do writeChannel (writer c) l- l' <- readChannel (reader d)- writeChannel out (Left l')- Right r -> writeChannel out (Right r)- ) <||> p (reader c) (writer d)- return ()-- right (ProcessPipeline p) = ProcessPipeline $ \in_ out -> do- c <- oneToOneChannel- d <- oneToOneChannel- (forever $ do x <- readChannel in_- case x of- Right r -> do writeChannel (writer c) r- r' <- readChannel (reader d)- writeChannel out (Right r')- Left l -> writeChannel out (Left l)- ) <||> p (reader c) (writer d)- return ()-- (ProcessPipeline p) ||| (ProcessPipeline q)- = ProcessPipeline $ \in_ out -> do- c <- oneToOneChannel- c' <- oneToOneChannel- d <- oneToOneChannel- d' <- oneToOneChannel- runParallel_- [ forever $ do x <- readChannel in_- x' <- case x of- Left l -> do writeChannel (writer c) l- readChannel (reader c')- Right r -> do writeChannel (writer d) r- readChannel (reader d')- writeChannel out x'- , p (reader c) (writer c')- , q (reader d) (writer d')- ]-- (ProcessPipeline p) +++ (ProcessPipeline q)- = ProcessPipeline $ \in_ out -> do- c <- oneToOneChannel- c' <- oneToOneChannel- d <- oneToOneChannel- d' <- oneToOneChannel- runParallel_- [ forever $ do x <- readChannel in_- x' <- case x of- Left l -> do writeChannel (writer c) l- l' <- readChannel (reader c')- return (Left l')- Right r -> do writeChannel (writer d) r- r' <- readChannel (reader d')- return (Right r')- writeChannel out x'- , p (reader c) (writer c')- , q (reader d) (writer d')- ]
Control/Concurrent/CHP/Base.hs view
@@ -38,10 +38,12 @@ import Control.Concurrent.STM import qualified Control.Exception.Extensible as C import Control.Monad.Error+import Control.Monad.LoopWhile import Control.Monad.Reader import Control.Monad.State import Control.Monad.Writer import Control.Monad.Trans+import Data.Function (on) import qualified Data.Map as Map import Data.Unique import System.IO@@ -137,11 +139,10 @@ AltableT alt _ -> alt liftTrace :: TraceT IO a -> CHP' a-liftTrace m = AltableT (badGuard "lifted action") m+liftTrace = AltableT (badGuard "lifted action") wrapPoison :: CHP a -> CHP' (WithPoison a)-wrapPoison (PoisonT m) = (liftM $ either (const PoisonItem) NoPoison) $- runErrorT m+wrapPoison (PoisonT m) = either (const PoisonItem) NoPoison <$> runErrorT m unwrapPoison :: CHP' (WithPoison a) -> CHP a unwrapPoison m = PoisonT (lift m) >>= checkPoison@@ -184,7 +185,7 @@ -- | Poisons all the given items. A handy shortcut for @mapM_ poison@. poisonAll :: (Poisonable c, MonadCHP m) => [c] -> m ()-poisonAll ps = mapM_ poison ps+poisonAll = mapM_ poison liftSTM :: MonadIO m => STM a -> m a@@ -250,7 +251,7 @@ } instance Eq (ManyToOneTVar a) where- (==) tvA tvB = mtoFinal tvA == mtoFinal tvB+ (==) = (==) `on` mtoFinal newManyToOneTVar :: (a -> Bool) -> STM a -> a -> STM (ManyToOneTVar a) newManyToOneTVar f r x@@ -301,6 +302,9 @@ instance MonadCHP CHP where liftCHP = id +instance MonadCHP m => MonadCHP (LoopWhileT m) where+ liftCHP = lift . liftCHP+ -- The monad is lazy, and very similar to the writer monad instance Monad CHP' where -- m :: AltableT g m a@@ -311,7 +315,10 @@ let altBody' = liftM (map $ second (>>= pullOutStandard . f)) altBody nonAlt' = nonAlt >>= pullOutStandard . f in AltableT altBody' nonAlt'- return x = AltableTRet x+ return = AltableTRet +instance Functor CHP' where+ fmap = liftM+ instance MonadIO CHP' where- liftIO m = liftTrace (liftIO m)+ liftIO = liftTrace . liftIO
− Control/Concurrent/CHP/Behaviours.hs
@@ -1,204 +0,0 @@--- Communicating Haskell Processes.--- Copyright (c) 2009, University of Kent.--- All rights reserved.--- --- Redistribution and use in source and binary forms, with or without--- modification, are permitted provided that the following conditions are--- met:------ * Redistributions of source code must retain the above copyright--- notice, this list of conditions and the following disclaimer.--- * Redistributions in binary form must reproduce the above copyright--- notice, this list of conditions and the following disclaimer in the--- documentation and/or other materials provided with the distribution.--- * Neither the name of the University of Kent nor the names of its--- contributors may be used to endorse or promote products derived from--- this software without specific prior written permission.------ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS--- IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,--- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR--- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR--- CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,--- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,--- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR--- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF--- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING--- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS--- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.----- | A module containing CHP behaviours. See 'offer' for details.------ This whole module was added in CHP 1.6.0.-module Control.Concurrent.CHP.Behaviours (- CHPBehaviour, offer, offerAll, alongside, alongside_, endWhen, once, upTo, repeatedly, repeatedly_,- repeatedlyRecurse, repeatedlyRecurse_) where--import Control.Applicative-import Control.Monad--import Control.Concurrent.CHP---- | This data represents a behaviour (potentially repeated) that will result in--- returning a value of type @a@. See 'offer' for more details.-data CHPBehaviour a = CHPBehaviour a (Maybe (CHP (CHPBehaviour a)))--instance Functor CHPBehaviour where- fmap f (CHPBehaviour x Nothing) = CHPBehaviour (f x) Nothing- fmap f (CHPBehaviour x (Just m)) = CHPBehaviour (f x) (Just $ fmap f <$> m)---- | Offers the given behaviour, and when it occurs, ends the entire call to 'offer'.--- Returns Just the result if the behaviour happens, otherwise gives Nothing.-endWhen :: CHP a -> CHPBehaviour (Maybe a)-endWhen m = CHPBehaviour Nothing (Just $ (\x -> CHPBehaviour (Just x) Nothing) <$> m)---- | Offers the given behaviour, and when it occurs, does not offer it again.--- Returns Just the result if the behaviour happens, otherwise gives Nothing.--- 'once' is different to 'endWhen' because the latter terminates the call to 'offer'--- regardless of other behaviours, whereas 'once' does not terminate the call to 'offer',--- it just won't be offered again during the call to 'offer'. Thus if you only--- offer some 'once' items without any 'endWhen', then after all the 'once' events--- have happened, the process will deadlock.------ @once m@ can be thought of as a shortcut for @listToMaybe <$> upTo1 m@-once :: CHP a -> CHPBehaviour (Maybe a)-once m = CHPBehaviour Nothing (Just $ (\x -> CHPBehaviour (Just x) (Just stop)) <$> m)----- | Offers the given behaviour up to the given number of times, returning a list--- of the results (in chronological order). Like 'once', when the limit is reached,--- the call to 'offer' is not terminated, so you still require an 'endWhen'.------ Added in version 1.8.0.-upTo :: Int -> CHP a -> CHPBehaviour [a]-upTo n m = reverse <$> upTo' []- where- upTo' xs- = CHPBehaviour xs $ Just $ if length xs >= n then stop else (upTo' . (:xs)) <$> m---- | Repeatedly offers the given behaviour until the outer call to 'offer' is terminated--- by an 'endWhen' event. A list is returned (in chronological order) of the results--- of each occurrence of the behaviour. @repeatedly@ is like an unbounded @upTo@.-repeatedly :: forall a. CHP a -> CHPBehaviour [a]-repeatedly m = reverse <$> repeatedly' []- where- repeatedly' :: [a] -> CHPBehaviour [a]- repeatedly' xs = CHPBehaviour xs $ Just $ - (\x -> repeatedly' (x:xs)) <$> m---- | Like 'repeatedly', but discards the output. Useful if the event is likely--- to occur a lot, and you don't need the results.-repeatedly_ :: CHP a -> CHPBehaviour ()-repeatedly_ m = CHPBehaviour () $ Just $ m >> return (repeatedly_ m)---- | Like 'repeatedly', but allows some state (of type @a@) to be passed from one--- subsequent call to another, as well as generating the results of type @b@.--- To begin with the function (first parameter) will be called with the initial--- state (second parameter). If chosen, it will return the new state, and a result--- to be accumulated into the list. The second call to the function will be passed--- the new state, to then return the even newer state and a second result, and--- so on.------ If you want to use this with the StateT monad transformer from the mtl library,--- you can call:------ > repeatedlyRecurse (runStateT myStateAction) initialState--- > where--- > myStateAction :: StateT s CHP a--- > initialState :: s-repeatedlyRecurse :: forall a b. (a -> CHP (b, a)) -> a -> CHPBehaviour [b]-repeatedlyRecurse f = fmap reverse . repeatedlyRecurse' []- where- repeatedlyRecurse' :: [b] -> a -> CHPBehaviour [b]- repeatedlyRecurse' rs x = CHPBehaviour rs $ Just $- (\(r, y) -> repeatedlyRecurse' (r : rs) y) <$> f x---- | Like 'repeatedlyRecurse', but does not accumulate a list of results.------ If you want to use this with the StateT monad transformer from the mtl library,--- you can call:------ > repeatedlyRecurse (execStateT myStateAction) initialState--- > where--- > myStateAction :: StateT s CHP a--- > initialState :: s-repeatedlyRecurse_ :: forall a. (a -> CHP a) -> a -> CHPBehaviour ()-repeatedlyRecurse_ f = repeatedlyRecurse'- where- repeatedlyRecurse' :: a -> CHPBehaviour ()- repeatedlyRecurse' x = CHPBehaviour () $ Just $ repeatedlyRecurse' <$> f x---- | Offers one behaviour alongside another, combining their semantics. See 'offer'.------ This operation is semantically associative and commutative.-alongside :: CHPBehaviour a -> CHPBehaviour b -> CHPBehaviour (a, b)-alongside oa@(CHPBehaviour a mfa) ob@(CHPBehaviour b mfb)- = CHPBehaviour (a, b) (do fa <- mfa- fb <- mfb- return $ (flip alongside ob <$> fa) <-> (alongside oa <$> fb)- )---- | Offers one behaviour alongside another, combining their semantics. See 'offer'.--- Unlike 'alongside', discards the output of the behaviours.------ This operation is associative and commutative.-alongside_ :: CHPBehaviour a -> CHPBehaviour b -> CHPBehaviour ()-alongside_ (CHPBehaviour _ mfa) (CHPBehaviour _ mfb)- = CHPBehaviour () (liftM2 (<->) (liftM blank <$> mfa) (liftM blank <$> mfb))- where- blank :: CHPBehaviour c -> CHPBehaviour ()- blank = fmap (const ())--infixr `alongside`---- | Offers the given behaviour until finished.------ For example,--- --- > offer $ repeatedly p `alongside` repeatedly q--- --- will repeatedly offer p and q without ever terminating. This:--- --- > offer $ repeatedly p `alongside` repeatedly q `alongside` endWhen r--- --- will offer p repeatedly and q repeatedly and r, until r happens, at which point--- the behaviour will end.--- This:--- --- > offer $ once p `alongside` endWhen q--- --- will offer p and q; if p happens first it will wait for q, but if q happens--- first it will finish. This:--- --- > offer $ once p `alongside` endWhen q `alongside` endWhen r--- --- permits p to happen at most once, while either of q or r happening will finish--- the call.------ All sorts of combinations are possible, but it is important to note that you--- need at least one 'endWhen' event if you ever intend the call to finish. Some--- laws involving 'offer' (ignoring the types and return values) are:------ > offer (repeatedly p) == forever p--- > offer (once p) == p >> stop -- i.e. it does not finish--- > offer (endWhen q) == Just <$> q--- > offer (endWhen p `alongside` endWhen q) == p <-> q--- > offer (once p `alongside` endWhen q) == (p >> q) <-> q------ Most other uses of 'offer' and 'alongside' do not reduce down to simple CHP--- programs, which is of course their attraction.-offer :: CHPBehaviour a -> CHP a-offer (CHPBehaviour x Nothing) = return x-offer (CHPBehaviour _x (Just m)) = m >>= offer---- | Offers all the given behaviours together, and gives back a list of the outcomes.--- --- This is roughly a shorthand for @offer . foldl1 alongside@, except that if you--- pass the empty list, you simply get the empty list returned (rather than an--- error)-offerAll :: [CHPBehaviour a] -> CHP [a]-offerAll [] = return []-offerAll bs = offer $ foldl1 (\x y -> fmap (uncurry (++)) $ alongside x y) bs'- where- bs' = map (fmap (:[])) bs
− Control/Concurrent/CHP/BroadcastChannels.hs
@@ -1,35 +0,0 @@--- Communicating Haskell Processes.--- Copyright (c) 2008--2009, University of Kent.--- All rights reserved.--- --- Redistribution and use in source and binary forms, with or without--- modification, are permitted provided that the following conditions are--- met:------ * Redistributions of source code must retain the above copyright--- notice, this list of conditions and the following disclaimer.--- * Redistributions in binary form must reproduce the above copyright--- notice, this list of conditions and the following disclaimer in the--- documentation and/or other materials provided with the distribution.--- * Neither the name of the University of Kent nor the names of its--- contributors may be used to endorse or promote products derived from--- this software without specific prior written permission.------ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS--- IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,--- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR--- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR--- CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,--- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,--- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR--- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF--- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING--- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS--- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.---- | Since version 1.5.0, this module is a synonym for the "Control.Concurrent.CHP.Channels.BroadcastReduce"--- module, and is liable to be removed in a future version.-module Control.Concurrent.CHP.BroadcastChannels- (module Control.Concurrent.CHP.Channels.BroadcastReduce) where--import Control.Concurrent.CHP.Channels.BroadcastReduce
− Control/Concurrent/CHP/Buffers.hs
@@ -1,145 +0,0 @@--- Communicating Haskell Processes.--- Copyright (c) 2008, University of Kent.--- All rights reserved.--- --- Redistribution and use in source and binary forms, with or without--- modification, are permitted provided that the following conditions are--- met:------ * Redistributions of source code must retain the above copyright--- notice, this list of conditions and the following disclaimer.--- * Redistributions in binary form must reproduce the above copyright--- notice, this list of conditions and the following disclaimer in the--- documentation and/or other materials provided with the distribution.--- * Neither the name of the University of Kent nor the names of its--- contributors may be used to endorse or promote products derived from--- this software without specific prior written permission.------ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS--- IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,--- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR--- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR--- CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,--- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,--- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR--- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF--- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING--- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS--- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.----- | Various processes that act like buffers. Poisoning either end of a buffer--- process is immediately passed on to the other side, in contrast to C++CSP2--- and JCSP.-module Control.Concurrent.CHP.Buffers (fifoBuffer, infiniteBuffer,- accumulatingInfiniteBuffer, overflowingBuffer, overwritingBuffer)- where--import Control.Monad-import Data.Foldable-import Data.Sequence (Seq, viewl, ViewL(..))-import qualified Data.Sequence as Seq--import Control.Concurrent.CHP-import qualified Control.Concurrent.CHP.Common as Common---- | Acts like a limited capacity FIFO buffer of the given size. When it is--- full it accepts no input, and when it is empty it offers no output.-fifoBuffer :: forall a. Int -> Chanin a -> Chanout a -> CHP ()-fifoBuffer n in_ out- | n < 0 = return ()- | n == 0 = Common.id in_ out- | otherwise = fifo Seq.empty `onPoisonRethrow` (poison in_ >> poison out)- where- fifo :: Seq a -> CHP ()- fifo s | Seq.null s = takeIn- | Seq.length s == n = sendOut- | otherwise = takeIn <-> sendOut- where- takeIn = readChannel in_ >>= fifo . addLast s- sendOut = do writeChannel out (seqHead s)- fifo (removeHead s)---- | Acts like a FIFO buffer with unlimited capacity. Use with caution; make--- sure you do not let the buffer grow so large that it eats up all your memory.--- When it is empty, it offers no output. It always accepts input.-infiniteBuffer :: forall a. Chanin a -> Chanout a -> CHP ()-infiniteBuffer in_ out- = buff Seq.empty `onPoisonRethrow` (poison in_ >> poison out)- where- buff :: Seq a -> CHP ()- buff s | Seq.null s = takeIn- | otherwise = sendOut </> takeIn- where- takeIn = readChannel in_ >>= buff . addLast s- sendOut = do writeChannel out (seqHead s)- buff (removeHead s)---- | Acts like a FIFO buffer with unlimited capacity, but accumulates--- sequential inputs into a list which it offers in a single output. Use with--- caution; make sure you do not let the buffer grow so large that it eats up--- all your memory. When it is empty, it offers the empty list. It always--- accepts input. Once it has sent out a value (or values) it removes them--- from its internal storage.------ Added in version 1.2.0.-accumulatingInfiniteBuffer :: forall a. Chanin a -> Chanout [a] -> CHP ()-accumulatingInfiniteBuffer in_ out- = buff Seq.empty `onPoisonRethrow` (poison in_ >> poison out)- where- buff :: Seq a -> CHP ()- buff s | Seq.null s = takeIn >>= buff- | otherwise = (sendOut </> takeIn) >>= buff- where- takeIn = liftM (addLast s) $ readChannel in_ - sendOut = do writeChannel out (toList s)- return Seq.empty----- | Acts like a FIFO buffer of limited capacity, except that when it is full,--- it always accepts input and discards it. When it is empty, it does not offer output.-overflowingBuffer :: forall a. Int -> Chanin a -> Chanout a -> CHP ()-overflowingBuffer n in_ out- | n < 0 = return ()- | n == 0 = Common.id in_ out- | otherwise = flow Seq.empty `onPoisonRethrow` (poison in_ >> poison out)- where- flow :: Seq a -> CHP ()- flow s | Seq.null s = takeIn- | Seq.length s == n = sendOut <-> dropItem- | otherwise = takeIn <-> sendOut- where- takeIn = readChannel in_ >>= flow . addLast s- dropItem = readChannel in_ >> flow s- sendOut = do writeChannel out (seqHead s)- flow (removeHead s)---- | Acts like a FIFO buffer of limited capacity, except that when it is full,--- it always accepts input and pushes out the oldest item in the buffer. When--- it is empty, it does not offer output.-overwritingBuffer :: forall a. Int -> Chanin a -> Chanout a -> CHP ()-overwritingBuffer n in_ out- | n < 0 = return ()- | n == 0 = Common.id in_ out- | otherwise = over Seq.empty `onPoisonRethrow` (poison in_ >> poison out)- where- over :: Seq a -> CHP ()- over s | Seq.null s = takeIn- | Seq.length s == n = sendOut <-> takeInOver- | otherwise = takeIn <-> sendOut- where- takeIn = readChannel in_ >>= over . addLast s- takeInOver = readChannel in_ >>= over . removeHead . addLast s- sendOut = do writeChannel out (seqHead s)- over (removeHead s)--seqHead :: Seq a -> a-seqHead s = case viewl s of- EmptyL -> error "Internal code logic error in buffer"- x :< _ -> x--removeHead :: Seq a -> Seq a-removeHead = Seq.drop 1--addLast :: Seq a -> a -> Seq a-addLast = (Seq.|>)
Control/Concurrent/CHP/CSP.hs view
@@ -52,13 +52,13 @@ -- First engages in event, then executes the body. The returned value is suitable -- for use in an alt buildOnEventPoison :: (Unique -> (Unique -> (Integer, Event.RecordedEventType)) -> [RecordedIndivEvent Unique]) -> Event.Event -> EventActions -> CHP a -> CHP a-buildOnEventPoison rec e act body+buildOnEventPoison recE e act body = liftPoison (AltableT (Right [(theGuard, return True)]) (return False)) >>= \b -> if b then body else alt [liftPoison $ AltableT (Right [(theGuard, return ())]) (return ())] >> body where- theGuard = EventGuard (rec (Event.getEventUnique e)) act [e]+ theGuard = EventGuard (recE (Event.getEventUnique e)) act [e] scopeBlock :: CHP a -> (a -> CHP b) -> IO () -> CHP b scopeBlock start body errorEnd@@ -71,14 +71,14 @@ wrapIndiv :: (Unique -> (Unique -> Integer) -> String -> [RecordedIndivEvent Unique]) -> Unique -> (Unique -> (Integer, Event.RecordedEventType)) -> [RecordedIndivEvent Unique]-wrapIndiv rec u lu = rec u (fst . lu) (Event.getEventTypeVal $ snd $ lu u)+wrapIndiv recE u lu = recE u (fst . lu) (Event.getEventTypeVal $ snd $ lu u) -- | 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. syncBarrierWith :: (Unique -> (Unique -> Integer) -> String -> [RecordedIndivEvent Unique]) -> (Int -> STM ()) -> Enrolled PhasedBarrier phase -> CHP phase-syncBarrierWith rec storeN (Enrolled (Barrier (e,tv, fph)))- = buildOnEventPoison (wrapIndiv rec) e (EventActions incPhase (return ()))+syncBarrierWith recE storeN (Enrolled (Barrier (e,tv, fph)))+ = buildOnEventPoison (wrapIndiv recE) e (EventActions incPhase (return ())) (liftIO $ atomically $ readTVar tv) where incPhase :: Map.Map Unique Int -> STM ()
Control/Concurrent/CHP/Channels.hs view
@@ -32,8 +32,8 @@ -- -- 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).+-- 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
Control/Concurrent/CHP/Channels/Base.hs view
@@ -169,8 +169,7 @@ case x of PoisonItem -> return PoisonItem NoPoison _ -> return $ NoPoison ())- sendWriteChannelC (STMChan (_, tv)) val- = sendData tv val+ sendWriteChannelC (STMChan (_, tv)) = sendData tv endWriteChannelC (STMChan (_, tv)) = consumeAck tv
Control/Concurrent/CHP/Channels/BroadcastReduce.hs view
@@ -109,8 +109,7 @@ instance Enrollable BroadcastChanin a where enroll c@(BI (BC (b,_,_))) f = enroll b (const $ f (Enrolled c))- resign (Enrolled (BI (BC (b,_,_)))) m- = resign (Enrolled b) m+ resign (Enrolled (BI (BC (b,_,_)))) = resign (Enrolled b) instance WriteableChannel BroadcastChanout where extWriteChannel' (BO (BC (b, tvSend, tvAck))) m@@ -141,8 +140,8 @@ checkForPoison (Enrolled (BI (BC (b,_,_)))) = checkForPoison $ Enrolled b newBroadcastChannel :: CHP (BroadcastChannel a)-newBroadcastChannel = do- do b@(Barrier (e, _, _)) <- newBarrier+newBroadcastChannel+ = do b@(Barrier (e, _, _)) <- newBarrier -- Writer is always enrolled: liftIO $ atomically $ enrollEvent e tvSend <- liftIO $ atomically $ newTVar Nothing@@ -208,8 +207,7 @@ instance Enrollable ReduceChanout a where enroll c@(GO (GC (b,_,_))) f = enroll b (const $ f (Enrolled c))- resign (Enrolled (GO (GC (b,_,_)))) m- = resign (Enrolled b) m+ resign (Enrolled (GO (GC (b,_,_)))) = resign (Enrolled b) instance WriteableChannel (Enrolled ReduceChanout) where extWriteChannel' (Enrolled (GO (GC (b, tv, (f,_))))) m@@ -246,8 +244,8 @@ checkForPoison (GI (GC (b,_,_))) = checkForPoison $ Enrolled b newReduceChannel :: Monoid a => CHP (ReduceChannel a)-newReduceChannel = do- do b@(Barrier (e, _, _)) <- newBarrier+newReduceChannel+ = do b@(Barrier (e, _, _)) <- newBarrier -- Writer is always enrolled: liftIO $ atomically $ enrollEvent e mtv <- liftIO $ atomically $ newManyToOneTVar ((== 0) . fst) (return (0, Nothing)) (0, Nothing)
Control/Concurrent/CHP/Channels/Communication.hs view
@@ -56,8 +56,9 @@ ReadableChannel(..), WriteableChannel(..), writeValue, writeChannelStrict ) where ++import Control.DeepSeq import Control.Monad-import Control.Parallel.Strategies import Data.Monoid import Control.Concurrent.CHP.Base@@ -85,7 +86,7 @@ -- | Starts the communication, then performs the given extended action, then -- sends the result of that down the channel. extWriteChannel :: chanEnd a -> CHP a -> CHP ()- extWriteChannel c m = extWriteChannel' c (liftM (flip (,) ()) m)+ extWriteChannel c = extWriteChannel' c . liftM (flip (,) ()) -- | Like extWriteChannel, but allows a value to be returned from the inner action. --@@ -120,7 +121,7 @@ -- -- Added in version 1.0.2. writeChannelStrict :: (NFData a, WriteableChannel chanEnd) => chanEnd a -> a -> CHP ()-writeChannelStrict c x = (writeChannel c $| rnf) x+writeChannelStrict c x = case rnf x of () -> writeChannel c x -- ========== -- Instances:
Control/Concurrent/CHP/Clocks.hs view
@@ -259,8 +259,8 @@ poisonTimerData :: TimerData time -> STM () poisonTimerData td- = do mapM_ poisonTVar $ map (snd . snd) (timerOffersAfter td)- mapM_ poisonTVar $ map (snd . snd) (timerOffersBefore td)+ = do mapM_ (poisonTVar . snd . snd) (timerOffersAfter td)+ mapM_ (poisonTVar . snd . snd) (timerOffersBefore td) maybe (return ()) (poisonTVar . snd) (timerOffersNext td) mapM_ poisonTVar $ timerEventPool td @@ -327,14 +327,14 @@ liftSTM (modifyTVar tv $ enrollTimerData $ Just ev) >>= checkPoison x <- f $ Enrolled tim- ts <- liftPoison $ liftTrace $ ask+ ts <- liftPoison . liftTrace $ ask liftSTM (modifyTVar' tv $ checkCompletion u sh ts . resignTimerData True) >>= checkPoison return x -- For temporary resignations, we don't touch the event pool resign (Enrolled (Clock (tv, u, sh))) m- = do ts <- liftPoison $ liftTrace $ ask+ = do ts <- liftPoison . liftTrace $ ask liftSTM (modifyTVar' tv (checkCompletion u sh ts . resignTimerData False)) >>= checkPoison x <- m@@ -406,7 +406,7 @@ -- to display times in traces. newClock :: (Ord time, Show time) => time -> CHP (Clock time) newClock t = do tv <- liftSTM $ newTVar $ NoPoison $ emptyTimerData t- u <- liftIO $ Event.newEventUnique+ u <- liftIO Event.newEventUnique return $ Clock (tv, u, show) -- | Creates a clock that starts at the given time, and gives it the given@@ -414,7 +414,7 @@ newClockWithLabel :: (Ord time, Show time) => time -> String -> CHP (Clock time) newClockWithLabel t l = do tv <- liftSTM $ newTVar $ NoPoison $ emptyTimerData t- u <- liftIO $ Event.newEventUnique+ u <- liftIO Event.newEventUnique liftPoison $ liftTrace $ labelUnique u l return $ Clock (tv, u, show) @@ -422,8 +422,8 @@ getCurrentTime (Enrolled (Clock (tv, _, _))) = liftSTM (liftM (fmap curTime) $ readTVar tv) >>= checkPoison wait c@(Enrolled (Clock (_, u, sh))) mt- = do ts <- liftPoison $ liftTrace $ ask- pid <- liftPoison $ liftTrace $ getProcessId+ = do ts <- liftPoison . liftTrace $ ask+ pid <- liftPoison . liftTrace $ getProcessId waitAct <- liftSTM $ waitClock pid ts c mt (t, s) <- liftSTM waitAct >>= checkPoison liftPoison $ liftTrace $ recordEvent [ClockSyncIndiv u s $ sh t]
− Control/Concurrent/CHP/Common.hs
@@ -1,307 +0,0 @@--- Communicating Haskell Processes.--- Copyright (c) 2008, University of Kent.--- All rights reserved.--- --- Redistribution and use in source and binary forms, with or without--- modification, are permitted provided that the following conditions are--- met:------ * Redistributions of source code must retain the above copyright--- notice, this list of conditions and the following disclaimer.--- * Redistributions in binary form must reproduce the above copyright--- notice, this list of conditions and the following disclaimer in the--- documentation and/or other materials provided with the distribution.--- * Neither the name of the University of Kent nor the names of its--- contributors may be used to endorse or promote products derived from--- this software without specific prior written permission.------ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS--- IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,--- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR--- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR--- CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,--- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,--- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR--- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF--- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING--- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS--- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.---- | A collection of useful common processes that are useful when plumbing--- together a process network. All the processes here rethrow poison when--- it is encountered, as this gives the user maximum flexibility (they can--- let it propagate it, or ignore it).------ The names here overlap with standard Prelude names. This is--- deliberate, as the processes act in a similar manner to the--- corresponding Prelude versions. It is expected that you will do--- something like:------ > import qualified Control.Concurrent.CHP.Common as Common------ or:------ > import qualified Control.Concurrent.CHP.Common as CHP------ to circumvent this problem.-module Control.Concurrent.CHP.Common where--import Control.Monad-import Control.Parallel.Strategies-import qualified Data.Traversable as Traversable-import Prelude (Bool(..), Maybe(..), Enum, Ord, ($), (<), Int, otherwise, (.))-import qualified Prelude--import Control.Concurrent.CHP---- | Forever forwards the value onwards, unchanged. Adding this to your process--- network effectively adds a single-place buffer.-id :: (ReadableChannel r, Poisonable (r a),- WriteableChannel w, Poisonable (w a)) => r a -> w a -> CHP ()-id in_ out = (forever $- do x <- readChannel in_- writeChannel out x- ) `onPoisonRethrow` (poison in_ >> poison out)---- | Forever forwards the value onwards. This is--- like 'id' but does not add any buffering to your network, and its presence--- is indetectable to the process either side.------ extId is a unit of the associative operator 'Control.Concurrent.CHP.Utils.|->|'.------ The behaviour of this process was corrected in version 1.1.0 to work properly--- when the reader of its output channel was offering choice.-extId :: Chanin a -> Chanout a -> CHP ()-extId in_ out = do- c <- oneToOneChannel- forever $- extReadChannel in_ (writeChannel (writer c))- <&>- extWriteChannel out (readChannel (reader c))---- | A process that waits for an input, then sends it out on /all/ its output--- channels (in order) during an extended rendezvous. This is often used to send the--- output on to both the normal recipient (without introducing buffering) and--- also to a listener process that wants to examine the value. If the listener--- process is first in the list, and does not take the input immediately, the--- value will not be sent to the other recipients until it does. The name--- of the process derives from the notion of a wire-tap, since the listener--- is hidden from the other processes (it does not visibly change the semantics--- for them -- except when the readers of the channels are offering a choice).-tap :: Chanin a -> [Chanout a] -> CHP ()-tap in_ outs = (forever $- extReadChannel in_- (\x -> mapM_ (Prelude.flip writeChannel x) outs)- ) `onPoisonRethrow` (poison in_ >> poisonAll outs)---- | Sends out a single value first (the prefix) then behaves like id.-prefix :: a -> Chanin a -> Chanout a -> CHP ()-prefix x in_ out = (writeChannel out x >> id in_ out)- `onPoisonRethrow` (poison in_ >> poison out)---- | Discards the first value it receives then act likes id.------ Added in version 1.5.0.-tail :: Chanin a -> Chanout a -> CHP ()-tail input output = do readChannel input `onPoisonRethrow` (poison input >> poison output)- id input output---- | Forever reads in a value, and then sends out its successor (using 'Prelude.succ').-succ :: Enum a => Chanin a -> Chanout a -> CHP ()-succ = map Prelude.succ---- | Reads in a value, and sends it out in parallel on all the given output--- channels.-parDelta :: Chanin a -> [Chanout a] -> CHP ()-parDelta in_ outs = (forever $- do x <- readChannel in_- runParallel_ $ Prelude.map (Prelude.flip writeChannel x) outs- ) `onPoisonRethrow` (poison in_ >> mapM_ poison outs)---- | Forever reads in a value, transforms it using the given function, and sends it--- out again. Note that the transformation is not applied strictly, so don't--- assume that this process will actually perform the computation. If you--- require a strict transformation, use 'map''.-map :: (a -> b) -> Chanin a -> Chanout b -> CHP ()-map f in_ out = forever (readChannel in_ >>= writeChannel out . f)- `onPoisonRethrow` (poison in_ >> poison out)---- | Like 'map', but applies the transformation strictly before sending on--- the value.------ Added in version 1.1.0.-map' :: NFData b => (a -> b) -> Chanin a -> Chanout b -> CHP ()-map' f in_ out = forever (readChannel in_ >>= writeChannelStrict out . f)- `onPoisonRethrow` (poison in_ >> poison out)---- | Forever reads in a value, and then based on applying the given function--- either discards it (if the function returns False) or sends it on (if--- the function returns True).-filter :: (a -> Bool) -> Chanin a -> Chanout a -> CHP ()-filter f in_ out = forever (do- x <- readChannel in_- when (f x) (writeChannel out x)- ) `onPoisonRethrow` (poison in_ >> poison out)---- | Streams all items in a 'Data.Traversable.Traversable' container out--- in the order given by 'Data.Traversable.mapM' on the output channel (one at--- a time). Lists, 'Prelude.Maybe', and 'Data.Set.Set' are all instances--- of 'Data.Traversable.Traversable', so this can be used for all of--- those.-stream :: Traversable.Traversable t => Chanin (t a) -> Chanout a -> CHP ()-stream in_ out = (forever $ do- xs <- readChannel in_- Traversable.mapM (writeChannel out) xs)- `onPoisonRethrow` (poison in_ >> poison out)---- | Forever waits for input from one of its many channels and sends it--- out again on the output channel.-merger :: [Chanin a] -> Chanout a -> CHP ()-merger ins out = (forever $ alt (Prelude.map readChannel ins) >>= writeChannel out)- `onPoisonRethrow` (poisonAll ins >> poison out)---- | Sends out the specified value on the given channel the specified number--- of times, then finishes.-replicate :: Int -> a -> Chanout a -> CHP ()-replicate n x c = replicateM_ n (writeChannel c x) `onPoisonRethrow` poison c---- | Forever sends out the same value on the given channel, until poisoned.--- Similar to the white-hole processes in some other frameworks.-repeat :: a -> Chanout a -> CHP ()-repeat x c = (forever $ writeChannel c x) `onPoisonRethrow` poison c---- | Forever reads values from the channel and discards them, until poisoned.--- Similar to the black-hole processes in some other frameworks.-consume :: Chanin a -> CHP ()-consume c = (forever $ readChannel c) `onPoisonRethrow` poison c---- | For the duration of the given process, acts as a consume process, but stops--- when the given process stops. Note that there could be a timing issue where--- extra inputs are consumed at the end of the lifetime of the process.--- Note also that while poison from the given process will be propagated on the--- consumption channel, there is no mechanism to propagate poison from the consumption--- channel into the given process.------ Added in version 1.2.0.-consumeAlongside :: Chanin a -> CHP b -> CHP b-consumeAlongside in_ proc- = do c <- oneToOneChannel' $ chanLabel "consumeAlongside-Internal"- (x,_) <- - ((do x <- proc- writeChannel (writer c) ()- return x- ) `onPoisonRethrow` poison (writer c))- <||>- (inner (reader c) `onPoisonRethrow` poison (reader c))- return x- where- inner c = do cont <- alt- [readChannel c >> return False- ,readChannel in_ >> return True- ]- if cont- then inner c- else return ()---- | Forever reads a value from both its input channels in parallel, then joins--- the two values using the given function and sends them out again. For example,--- @join (,) c d@ will pair the values read from @c@ and @d@ and send out the--- pair on the output channel, whereas @join (&&)@ will send out the conjunction--- of two boolean values, @join (==)@ will read two values and output whether--- they are equal or not, etc.-join :: (a -> b -> c) -> Chanin a -> Chanin b -> Chanout c -> CHP ()-join f in0 in1 out = (forever $ do- [Prelude.Left x, Prelude.Right y] <- runParallel- [liftM Prelude.Left $ readChannel in0, liftM Prelude.Right $ readChannel in1]- writeChannel out $ f x y- ) `onPoisonRethrow` (poison in0 >> poison in1 >> poison out)---- | Forever reads a value from all its input channels in parallel, then joins--- the values into a list in the same order as the channels, and sends them out again.-joinList :: [Chanin a] -> Chanout [a] -> CHP ()-joinList ins out = (forever $ runParMapM readChannel ins >>= writeChannel out- ) `onPoisonRethrow` (poisonAll ins >> poison out)----- | Forever reads a pair from its input channel, then in parallel sends out--- the first and second parts of the pair on its output channels.------ Added in version 1.0.2.-split :: Chanin (a, b) -> Chanout a -> Chanout b -> CHP ()-split in_ outA outB = (forever $ do- (a, b) <- readChannel in_- writeChannel outA a <||> writeChannel outB b- ) `onPoisonRethrow` (poison in_ >> poison outA >> poison outB)---- | A sorter process. When it receives its first @Just x@ data item, it keeps--- it. When it receieves a second, it keeps the lowest of the two, and sends--- out the other one. When it receives Nothing, it sends out its data value,--- then sends Nothing too. The overall effect when chaining these things together--- is a sorting pump. You inject all the values with Just, then send in a--- single Nothing to get the results out (in reverse order).-sorter :: Ord a => Chanin (Maybe a) -> Chanout (Maybe a) -> CHP ()-sorter = sorter' (<)---- | Like sorter, but with a custom comparison method. You should pass in--- the equivalent of less-than: (<).-sorter' :: forall a. (a -> a -> Bool) -> Chanin (Maybe a) -> Chanout (Maybe a) -> CHP ()-sorter' lt in_ out = internal Nothing `onPoisonRethrow` (poison in_ >> poison out)- where- internal :: Maybe a -> CHP ()- internal curVal = do newVal <- readChannel in_- case (curVal, newVal) of- -- Flush, but we're empty:- (Nothing, Nothing) -> do writeChannel out newVal- internal curVal- -- Flush:- (Just _, Nothing) -> do writeChannel out curVal- writeChannel out newVal- internal curVal- -- New value, we were empty:- (Nothing, Just _) -> internal newVal- -- New value, we had one already:- (Just cur, Just new)- | new `lt` cur -> do writeChannel out curVal- internal newVal- | otherwise -> do writeChannel out newVal- internal curVal---- | A shared variable process. Given an initial value and two channels, it--- continually offers to output its current value or read in a new one.------ Added in version 1.1.1------ Note that prior to version 1.2.0 (i.e. in version 1.1.1) there was a bug where--- poison would not be propagated between the input and output.-valueStore :: (ReadableChannel r, Poisonable (r a),- WriteableChannel w, Poisonable (w a)) =>- a -> r a -> w a -> CHP ()-valueStore val input output- = inner val `onPoisonRethrow` (poison input >> poison output)- where- inner x = ((writeChannel output x >> return x) <-> readChannel input) >>= inner---- | A shared variable process. The same as valueStore, but initially waits--- to read its starting value before then offering to either output its current--- value or read in a new one.------ Added in version 1.1.1------ Note that prior to version 1.2.0 (i.e. in version 1.1.1) there was a bug where--- poison would not be propagated between the input and output.-valueStore' :: (ReadableChannel r, Poisonable (r a),- WriteableChannel w, Poisonable (w a)) => r a -> w a -> CHP ()-valueStore' input output- = (readChannel input >>= \x -> valueStore x input output)- `onPoisonRethrow` (poison input >> poison output)---- | Continually waits for a specific time on the given clock, each time applying--- the function to work out the next specific time to wait for. The most common--- thing to pass is Prelude.succ or (+1).------ Added in version 1.2.0.-advanceTime :: (Waitable c, Ord t) => (t -> t) -> Enrolled c t -> CHP ()-advanceTime f c = do t <- getCurrentTime c- inner (f t)- where- inner t = wait c (Just t) >>= inner . f
− Control/Concurrent/CHP/Connect.hs
@@ -1,232 +0,0 @@--- Communicating Haskell Processes.--- Copyright (c) 2008--2009, University of Kent.--- All rights reserved.--- --- Redistribution and use in source and binary forms, with or without--- modification, are permitted provided that the following conditions are--- met:------ * Redistributions of source code must retain the above copyright--- notice, this list of conditions and the following disclaimer.--- * Redistributions in binary form must reproduce the above copyright--- notice, this list of conditions and the following disclaimer in the--- documentation and/or other materials provided with the distribution.--- * Neither the name of the University of Kent nor the names of its--- contributors may be used to endorse or promote products derived from--- this software without specific prior written permission.------ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS--- IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,--- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR--- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR--- CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,--- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,--- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR--- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF--- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING--- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS--- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.---- | A module of operators for connecting processes together.------ This whole module was added in version 1.7.0.-module Control.Concurrent.CHP.Connect- (Connectable(..), (<=>), (|<=>), (<=>|), (|<=>|), pipelineConnect, pipelineConnectComplete,- pipelineConnectCompleteT, cycleConnect, connectList, connectList_, ChannelPair,- ConnectableExtra(..), connectWith) where--import Control.Applicative-import Control.Arrow--import Control.Concurrent.CHP---- | Like 'Connectable', but allows an extra parameter.------ The API (and name) for this is still in flux, so do not rely on it just yet.-class ConnectableExtra l r where- type ConnectableParam l- -- | Runs the given code with the two items connected.- connectExtra :: ConnectableParam l -> ((l, r) -> CHP ()) -> CHP ()---- | Indicates that its two parameters can be joined together automatically.------ Rather than use 'connect' directly, you will want to use the operators such--- as '(<=>)'. There are different forms of this operator for in the middle of--- a pipeline (where you still need further parameters to each process), and at--- the ends. See also 'pipelineConnect' and 'pipelineConnectComplete'.-class Connectable l r where- -- | Runs the given code with the two items connected.- --- -- The type of this function was generalised in CHP 1.8.0- -- from @((l, r) -> CHP ()) -> CHP ()@ to @((l, r) -> CHP a) -> CHP a@- connect :: ((l, r) -> CHP a) -> CHP a---- | A pair of channels. The main use of this type is with the Connectable class,--- as it allows you to wire together two processes that take the exact same channel--- pair, e.g. both are of type @ChannelPair (Chanin Int) (Chanout Int) -> CHP ()@. With the--- normal Connectable pair instances, one would need to be of type @(Chanin Int,--- Chanout Int) -> CHP ()@, and the other of type @(Chanout Int, Chanin Int) ->--- CHP ()@.-data ChannelPair l r = ChannelPair l r- deriving (Eq, Show)--instance Connectable l r => Connectable (ChannelPair l r) (ChannelPair l r) where- connect f = connect $ \(lx, rx) -> connect $ \(ly, ry) -> - f (ChannelPair lx ry, ChannelPair ly rx)---- | Like 'connect', but provides the process a list of items of the specified size,--- and runs it.------ This function was added in version 1.8.0.-connectList :: Connectable l r => Int -> ([(l, r)] -> CHP a) -> CHP a-connectList n p | n == 0 = p []- | n > 0 = connect $ \lr -> connectList (n - 1) $ p . (lr :)- | otherwise = error $ "Control.Concurrent.CHP.Connect.connectList: negative parameter " ++ show n---- | Like 'connectList' but ignores the results.------ This function was added in version 1.8.0.-connectList_ :: Connectable l r => Int -> ([(l, r)] -> CHP a) -> CHP ()-connectList_ n p | n == 0 = p [] >> return ()- | n > 0 = connect $ \lr -> connectList_ (n - 1) $ p . (lr :)- | otherwise = error $ "Control.Concurrent.CHP.Connect.connectList_: negative parameter " ++ show n---- | Joins together the given two processes and runs them in parallel.-(|<=>|) :: Connectable l r => (l -> CHP ()) -> (r -> CHP ()) -> CHP ()-(|<=>|) p q = connect $ \(x, y) -> p x <|*|> q y--jpo :: ConnectableExtra l r => ConnectableParam l -> (l -> CHP ()) -> (r -> CHP ()) -> CHP ()-jpo o p q = connectExtra o $ \(x, y) -> p x <|*|> q y---- | Joins together the given two processes and runs them in parallel.-(<=>) :: Connectable l r => (a -> l -> CHP ()) -> (r -> b -> CHP ()) -> a -> b -> CHP ()-(<=>) p q x y = p x |<=>| flip q y---- | Joins together the given two processes and runs them in parallel.-(<=>|) :: Connectable l r => (a -> l -> CHP ()) -> (r -> CHP ()) -> a -> CHP ()-(<=>|) p q x = p x |<=>| q---- | Joins together the given two processes and runs them in parallel.-(|<=>) :: Connectable l r => (l -> CHP ()) -> (r -> b -> CHP ()) -> b -> CHP ()-(|<=>) p q x = p |<=>| flip q x---- | Like '(<=>)' but with 'ConnectableExtra'-connectWith :: ConnectableExtra l r => ConnectableParam l ->- (a -> l -> CHP ()) -> (r -> b -> CHP ()) -> a -> b -> CHP ()-connectWith o p q x y = jpo o (p x) (flip q y)---- | Like @foldl1 (<=>)@; connects a pipeline of processes together. If the list--- is empty, it returns a process that ignores both its arguments and returns instantly.-pipelineConnect :: Connectable l r => [r -> l -> CHP ()] -> r -> l -> CHP ()-pipelineConnect [] = const . const $ return ()-pipelineConnect ps = foldl1 (<=>) ps---- | Connects the given beginning process, the list of middle processes, and--- the end process into a pipeline and runs them all in parallel. If the list--- is empty, it connects the beginning directly to the end.-pipelineConnectComplete :: Connectable l r =>- (l -> CHP ()) -> [r -> l -> CHP ()] -> (r -> CHP ()) -> CHP ()-pipelineConnectComplete begin middle end- = (foldl (|<=>) begin middle) |<=>| end---- | Like 'pipelineConnectComplete' but allows a customised function to run all--- the processes in parallel. So @pipelineConnectCompleteT runParallel@ is the--- same as @pipelineConnectComplete@. The list of items given to the first function--- will be in the order: begin process, middle processes, end process, as you would--- expect.------ This function was added in version 1.8.0.-pipelineConnectCompleteT :: Connectable l r =>- ([a] -> CHP b) -> (l -> a) -> [r -> l -> a] -> (r -> a) -> CHP b-pipelineConnectCompleteT run begin [] end- = connect $ \(l, r) -> run [begin l, end r]-pipelineConnectCompleteT run begin (p:ps) end- = connect $ \(l, r) ->- pipelineConnectCompleteT (run . (begin l :)) (p r) ps end---- | Like 'pipelineConnect' but also connects the last process into the first.--- If the list is empty, it returns immediately.-cycleConnect :: Connectable l r => [r -> l -> CHP ()] -> CHP ()-cycleConnect [] = return ()-cycleConnect ps = connect . uncurry . flip . pipelineConnect $ ps--instance Connectable (Chanout a) (Chanin a) where- connect = (>>=) ((writer &&& reader) <$> oneToOneChannel)-instance ConnectableExtra (Chanout a) (Chanin a) where- type ConnectableParam (Chanout a) = ChanOpts a- connectExtra o = (>>=) ((writer &&& reader) <$> oneToOneChannel' o)--instance Connectable (Chanin a) (Chanout a) where- connect = (>>=) ((reader &&& writer) <$> oneToOneChannel)-instance ConnectableExtra (Chanin a) (Chanout a) where- type ConnectableParam (Chanin a) = ChanOpts a- connectExtra o = (>>=) ((reader &&& writer) <$> oneToOneChannel' o)--instance Connectable (Enrolled PhasedBarrier ()) (Enrolled PhasedBarrier ()) where- connect m = do b <- newBarrier- enroll b $ \b0 -> enroll b $ \b1 -> m (b0, b1)--instance ConnectableExtra (Enrolled PhasedBarrier ph) (Enrolled PhasedBarrier ph) where- type ConnectableParam (Enrolled PhasedBarrier ph) = (ph, BarOpts ph)- connectExtra (ph, o) m- = do b <- newPhasedBarrier' ph o- enroll b $ \b0 -> enroll b $ \b1 -> m (b0, b1)---instance (Connectable al ar, Connectable bl br) => Connectable (al, bl) (ar, br) where- connect m = connect $ \(ax, ay) -> connect $ \(bx, by) -> m ((ax, bx), (ay, by))-instance (ConnectableExtra al ar, ConnectableExtra bl br) => ConnectableExtra (al, bl) (ar, br) where- type ConnectableParam (al, bl) = (ConnectableParam al, ConnectableParam bl)- connectExtra (ao, bo) m = connectExtra ao $ \(ax, ay) -> connectExtra bo $ \(bx, by) -> m ((ax, bx), (ay, by))--instance (Connectable al ar, Connectable bl br, Connectable cl cr) =>- Connectable (al, bl, cl) (ar, br, cr) where- connect m = connect $ \(ax, ay) -> connect $ \(bx, by) ->- connect $ \(cx, cy) -> m ((ax, bx, cx), (ay, by, cy))--instance (ConnectableExtra al ar, ConnectableExtra bl br, ConnectableExtra cl cr) =>- ConnectableExtra (al, bl, cl) (ar, br, cr) where- type ConnectableParam (al, bl, cl) = (ConnectableParam al, ConnectableParam bl, ConnectableParam cl)- connectExtra (ao, bo, co) m- = connectExtra ao $ \(ax, ay) -> connectExtra bo $ \(bx, by) ->- connectExtra co $ \(cx, cy) -> m ((ax, bx, cx), (ay, by, cy))--instance (Connectable al ar, Connectable bl br, Connectable cl cr,- Connectable dl dr) =>- Connectable (al, bl, cl, dl) (ar, br, cr, dr) where- connect m = connect $ \(ax, ay) -> connect $ \(bx, by) ->- connect $ \(cx, cy) -> connect $ \(dx, dy) ->- m ((ax, bx, cx, dx), (ay, by, cy, dy))-instance (ConnectableExtra al ar, ConnectableExtra bl br, ConnectableExtra cl cr,- ConnectableExtra dl dr) =>- ConnectableExtra (al, bl, cl, dl) (ar, br, cr, dr) where- type ConnectableParam (al, bl, cl, dl)- = (ConnectableParam al,- ConnectableParam bl,- ConnectableParam cl,- ConnectableParam dl)- connectExtra (ao, bo, co, do_) m- = connectExtra ao $ \(ax, ay) -> connectExtra bo $ \(bx, by) ->- connectExtra co $ \(cx, cy) -> connectExtra do_ $ \(dx, dy) ->- m ((ax, bx, cx, dx), (ay, by, cy, dy))--instance (Connectable al ar, Connectable bl br, Connectable cl cr,- Connectable dl dr, Connectable el er) =>- Connectable (al, bl, cl, dl, el) (ar, br, cr, dr, er) where- connect m = connect $ \(ax, ay) -> connect $ \(bx, by) ->- connect $ \(cx, cy) -> connect $ \(dx, dy) ->- connect $ \(ex, ey) -> m ((ax, bx, cx, dx, ex), (ay, by, cy, dy, ey))-instance (ConnectableExtra al ar, ConnectableExtra bl br, ConnectableExtra cl cr,- ConnectableExtra dl dr, ConnectableExtra el er) =>- ConnectableExtra (al, bl, cl, dl, el) (ar, br, cr, dr, er) where- type ConnectableParam (al, bl, cl, dl, el)- = (ConnectableParam al,- ConnectableParam bl,- ConnectableParam cl,- ConnectableParam dl,- ConnectableParam el)- connectExtra (ao, bo, co, do_, eo) m- = connectExtra ao $ \(ax, ay) -> connectExtra bo $ \(bx, by) ->- connectExtra co $ \(cx, cy) -> connectExtra do_ $ \(dx, dy) ->- connectExtra eo $ \(ex, ey) -> m ((ax, bx, cx, dx, ex), (ay, by, cy, dy, ey))-
− Control/Concurrent/CHP/Connect/TwoDim.hs
@@ -1,231 +0,0 @@--- Communicating Haskell Processes.--- Copyright (c) 2008--2009, University of Kent.--- All rights reserved.--- --- Redistribution and use in source and binary forms, with or without--- modification, are permitted provided that the following conditions are--- met:------ * Redistributions of source code must retain the above copyright--- notice, this list of conditions and the following disclaimer.--- * Redistributions in binary form must reproduce the above copyright--- notice, this list of conditions and the following disclaimer in the--- documentation and/or other materials provided with the distribution.--- * Neither the name of the University of Kent nor the names of its--- contributors may be used to endorse or promote products derived from--- this software without specific prior written permission.------ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS--- IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,--- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR--- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR--- CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,--- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,--- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR--- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF--- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING--- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS--- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.---- | This module contains helper functions for wiring up collections of processes--- into a two-dimensional arrangement.------ This module was added in version 1.8.0.-module Control.Concurrent.CHP.Connect.TwoDim- (FourWay(..), wrappedGridFour, wrappedGridFour_,- FourWayDiag(..), EightWay, wrappedGridEight, wrappedGridEight_) where--import Control.Arrow-import Control.Concurrent.CHP-import Control.Concurrent.CHP.Connect-import Control.Monad-import Data.List--import Prelude hiding (abs)---- | A data type representing four-way connectivity for a process, with channels--- to the left and right, above and below.-data FourWay above below left right- = FourWay { above :: above, below :: below, left :: left, right :: right }- deriving (Eq)---- | A data type representing four-way diagonal connectivity for a process, with--- channels above-left, below-right, above-right and below-left.-data FourWayDiag aboveLeft belowRight aboveRight belowLeft- = FourWayDiag { aboveLeft :: aboveLeft, belowRight :: belowRight, aboveRight :: aboveRight, belowLeft :: belowLeft }- deriving (Eq)---- | EightWay is simply a synonym for a pair of 'FourWay' and 'FourWayDiag'.-type EightWay a b l r al br ar bl = (FourWay a b l r, FourWayDiag al br ar bl)---- | Wires the given grid of processes (that require four-way connectivity) together--- into a wrapped around grid (a torus) and runs them all in parallel.------ The parameter is a list of rows, and should be rectangular (i.e. all the rows--- should be the same length). If not, an error will result. The return value--- is guaranteed to be the same shape as the input.------ It is worth remembering that if you have only one row or one column (or--- both), processes can be connected to themselves, so make sure that if a--- process is connected to itself (e.g. its left channel connects to its right--- channel), it is coded such that it won't deadlock -- or if needed, checks for this--- possibility using 'sameChannel'. Processes may also be connected to each other--- multiple times -- in a two-wide grid, each process's left channel connects to--- the same process as its right.-wrappedGridFour :: (Connectable above below, Connectable left right) =>- [[FourWay above below left right -> CHP a]] -> CHP [[a]]-wrappedGridFour ps- -- If ps == [], this will succeed, and map connectRowCycle ps will be [],- -- and thus connectColumnsCycle _ [] will return [] (without forcing the- -- head call), and it will all work correctly.- | length (nub $ map length ps) <= 1- = connectColumnsCycle (length (head ps)) $ map connectRowCycle ps- | otherwise- = error $ "Control.Concurrent.CHP.Connect.TwoDim.wrappedGrid: Non-rectangular input "- ++ " height: " ++ show (length ps) ++ " widths: " ++ show (map length ps)---- | Like 'wrappedGridFour' but discards the return values.-wrappedGridFour_ :: (Connectable above below, Connectable left right) =>- [[FourWay above below left right -> CHP a]] -> CHP ()-wrappedGridFour_ ps = wrappedGridFour ps >> return () --TODO fix this---- | Like 'wrappedGridFour' but provides eight-way connectivity.------ The note on 'wrappedGridFour' about processes being connected to themselves--- applies here too -- as does the note about processes being connected to--- each other multiple times. If you have one row, a process's left,--- above-left and below-left channels all connect to the same process. If you--- have a two-by-two grid, a process's four diagonal channels all connect to--- the same process.-wrappedGridEight :: (Connectable above below, Connectable left right,- Connectable aboveLeft belowRight, Connectable belowLeft aboveRight) =>- [[EightWay above below left right aboveLeft belowRight aboveRight belowLeft -> CHP a]] -> CHP [[a]]-wrappedGridEight ps- | length (nub $ map length ps) <= 1- = connectColumnsCycleDiag (length (head ps)) $ map connectRowCycleDiag ps- | otherwise- = error $ "Control.Concurrent.CHP.Connect.TwoDim.wrappedGridDiag: Non-rectangular input "- ++ " height: " ++ show (length ps) ++ " widths: " ++ show (map length ps)---- | Like 'wrappedGridEight' but discards the output.-wrappedGridEight_ :: (Connectable above below, Connectable left right,- Connectable aboveLeft belowRight, Connectable belowLeft aboveRight) =>- [[EightWay above below left right aboveLeft belowRight aboveRight belowLeft -> CHP a]] -> CHP ()-wrappedGridEight_ ps = wrappedGridEight ps >> return ()---connectRowCycle :: Connectable left right =>- [FourWay above below left right -> CHP a] -> ([(above, below)] -> CHP [a])-connectRowCycle [] _ = return []-connectRowCycle allps abs = connect $- foldr connLR- -- The last process is special because it must take both channels for itself:- (liftM (:[]) . last allps . uncurry (uncurry FourWay $ last abs))- (zip (init allps) (init abs))--connLR :: Connectable left right =>- (FourWay above below left right -> CHP a, (above, below))- -> ((left, right) -> CHP [a])- -> ((left, right) -> CHP [a])-connLR (p, (a, b)) q (l, r)- = liftM (uncurry (:)) . connect $ \(l', r') -> p (FourWay a b l r') <||> q (l', r)--connectColumnsCycle :: Connectable above below => Int -> [[(above, below)] -> CHP [a]] -> CHP [[a]]-connectColumnsCycle _ [] = return []-connectColumnsCycle n ps = connectList n $ foldl1 (connAB n) (map (liftM (:[]) .) ps)--connAB :: Connectable above below => Int -> ([(above, below)] -> CHP [a]) -> ([(above, below)] -> CHP [a]) -> ([(above, below)] -> CHP [a])-connAB n p q abs = liftM (uncurry (++)) $ connectList n $ \abs' -> p (zip (map fst abs) (map snd abs'))- <||> q (zip (map fst abs') (map snd abs))--connectColumnsCycleDiag :: (Connectable a b, Connectable bl ar, Connectable al br) =>- Int -> [[((a, b), FourWayDiag al br ar bl)] -> CHP [z]] -> CHP [[z]]-connectColumnsCycleDiag _ [] = return []-connectColumnsCycleDiag n ps = connectList n $ \abs ->- connectList n $ \leadingDiag -> connectList n $ \otherDiag ->- foldl1 (connABDiag n) (map (liftM (:[]) .) ps)- $ zip abs [FourWayDiag al br ar bl- | (_, ar) <- otherDiag- | (bl, _) <- shiftRight otherDiag- | (al, _) <- leadingDiag- | (_, br) <- shiftLeft leadingDiag]---- Let's imagine we have a square:------ A B C--- D E F--- G H I------ We pass in the outer-most channels as the processes need them to be wired.------ So for example, A will recieve:--- aboveLeft: AI--- aboveRight AH--- belowLeft: AF--- belowRight: AE------ So for example when we create the leadingDiag channels:------ \1 \2 \3 --- A B C------ The ends are passed to the above channels as-is, but to the below channels shifted lleft:------ G H I--- \2 \3 \1------ For the otherDiag, shifted right when below:------ /1 /2 /3--- A B C------ G H I--- /3 /1 /2--shiftLeft, shiftRight :: [a] -> [a]-shiftLeft [] = []-shiftLeft xs = tail xs ++ [head xs]-shiftRight [] = []-shiftRight xs = last xs : init xs--connABDiag :: (Connectable above below, Connectable al br, Connectable bl ar) =>- Int -> ([((above, below), FourWayDiag al br ar bl)] -> CHP [a])- -> ([((above, below), FourWayDiag al br ar bl)] -> CHP [a])- -> ([((above, below), FourWayDiag al br ar bl)] -> CHP [a])-connABDiag n p q abs = liftM (uncurry (++)) $ connectList n $ \abs' ->- connectList n $ \leadingDiag -> connectList n $ \otherDiag ->- p [((a, b), FourWayDiag al br ar bl)- | ((a, _), _) <- abs- | (_, b) <- abs'- | (_, FourWayDiag al _ ar _) <- abs- | (bl, _) <- shiftRight otherDiag- | (_, br) <- shiftLeft leadingDiag- ]- <||>- q [((a, b), FourWayDiag al br ar bl)- | ((_, b), _) <- abs- | (a, _) <- abs'- | (al, _) <- leadingDiag- | (_, ar) <- otherDiag- | (_, FourWayDiag _ br _ bl) <- abs- ]--- We are given our own above and below as we need them to be arranged already.---connectRowCycleDiag :: Connectable l r =>- [EightWay a b l r al br ar bl -> CHP z]- -> ([((a, b), FourWayDiag al br ar bl)] -> CHP [z])-connectRowCycleDiag [] _ = return []-connectRowCycleDiag allps abs = connect $- foldr connLRDiag- -- The last process is special because it must take both channels for itself:- (\lr -> liftM (:[]) $ last allps $ first (($ lr) . uncurry . uncurry FourWay) (last abs))- (zip (init allps) (init abs))---connLRDiag :: Connectable l r =>- (EightWay a b l r al br ar bl -> CHP z, ((a, b), FourWayDiag al br ar bl))- -> ((l, r) -> CHP [z])- -> ((l, r) -> CHP [z])-connLRDiag (p, ((a, b), diag)) q (l, r)- = liftM (uncurry (:)) . connect $ \(l', r') -> p (FourWay a b l r', diag) <||> q (l', r)
− Control/Concurrent/CHP/Console.hs
@@ -1,114 +0,0 @@--- Communicating Haskell Processes.--- Copyright (c) 2008, University of Kent.--- All rights reserved.--- --- Redistribution and use in source and binary forms, with or without--- modification, are permitted provided that the following conditions are--- met:------ * Redistributions of source code must retain the above copyright--- notice, this list of conditions and the following disclaimer.--- * Redistributions in binary form must reproduce the above copyright--- notice, this list of conditions and the following disclaimer in the--- documentation and/or other materials provided with the distribution.--- * Neither the name of the University of Kent nor the names of its--- contributors may be used to endorse or promote products derived from--- this software without specific prior written permission.------ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS--- IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,--- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR--- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR--- CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,--- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,--- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR--- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF--- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING--- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS--- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.---- | Contains a process for easily using stdin, stdout and stderr as channels.-module Control.Concurrent.CHP.Console where--import Control.Concurrent-import Control.Concurrent.STM-import qualified Control.Exception.Extensible as C-import Control.Monad-import Control.Monad.Trans---import Data.Maybe-import System.IO--import Control.Concurrent.CHP---- | A set of channels to be given to the process to run, containing channels--- for stdin, stdout and stderr.-data ConsoleChans = ConsoleChans { cStdin :: Chanin Char, cStdout :: Chanout- Char, cStderr :: Chanout Char }---- | A function for running the given CHP process that wants console channels.--- When your program finishes, the console channels are automatically poisoned,--- but it's good practice to poison them yourself when you finish. Only ever--- run one of these processes at a time, or undefined behaviour will result.------ When using this process, due to the way that the console handlers are terminated,--- you may sometimes see a notice that a thread was killed. This is normal behaviour--- (unfortunately).-consoleProcess :: (ConsoleChans -> CHP ()) -> CHP ()-consoleProcess mainProc- = do [cin, cout, cerr] <- replicateM 3 oneToOneChannel- tvs@[tvinId, tvoutId, tverrId] <- liftIO $ atomically $ replicateM 3 $ newTVar Nothing- runParallel_- [ inHandler tvinId (writer cin)- , outHandler tvoutId stdout (reader cout)- , outHandler tverrId stderr (reader cerr)- , do ids <- mapM getId tvs- (mainProc $ ConsoleChans (reader cin) (writer cout) (writer cerr))- `onPoisonTrap` (return ())- poison (reader cin)- poison (writer cout)- poison (writer cerr)- -- Poison won't do it if the handlers are blocked on input or- -- output. Therefore we throw them an exception to "knock them- -- off" their current action and make them exit.- liftIO yield- liftIO $ mapM_ killThread ids- ]- where- getId :: TVar (Maybe a) -> CHP a- getId tv = liftIO $ atomically $ readTVar tv >>= maybe retry return-- -- Like liftIO, but turns any caught exceptions into throwing poison- liftIO' :: IO a -> CHP a- liftIO' m = liftIO (liftM Just m `C.catches` handlers)- >>= maybe throwPoison return- where- response :: C.Exception e => e -> IO (Maybe a)- response = const $ return Nothing-- handlers = [C.Handler (response :: C.IOException -> IO (Maybe a))- ,C.Handler (response :: C.AsyncException -> IO (Maybe a))-#if __GLASGOW_HASKELL__ >= 611- ,C.Handler (response :: C.BlockedIndefinitelyOnSTM -> IO (Maybe a))-#else- ,C.Handler (response :: C.BlockedIndefinitely -> IO (Maybe a))-#endif- ,C.Handler (response :: C.Deadlock -> IO (Maybe a))- ]- - inHandler :: TVar (Maybe ThreadId) -> Chanout Char -> CHP ()- inHandler tv c- = do liftIO $ myThreadId >>= atomically . writeTVar tv . Just- if rtsSupportsBoundThreads- then (forever $ do ready <- liftIO $ hWaitForInput stdin 100- checkForPoison c- when ready $- liftIO' getChar >>= writeChannel c)- `onPoisonTrap` (poison c)- else (forever $ liftIO' getChar >>= writeChannel c)- `onPoisonTrap` (poison c)-- outHandler :: TVar (Maybe ThreadId) -> Handle -> Chanin Char -> CHP ()- outHandler tv h c- = do liftIO $ myThreadId >>= atomically . writeTVar tv . Just- (forever $ readChannel c >>= liftIO' . hPutChar h)- `onPoisonTrap` (poison c)
Control/Concurrent/CHP/Enroll.hs view
@@ -74,7 +74,7 @@ -- | Like 'enroll' but enrolls on the given list of barriers enrollList :: Enrollable b p => [b p] -> ([Enrolled b p] -> CHP a) -> CHP a enrollList [] f = f []-enrollList (b:bs) f = enroll b $ \eb -> enrollList bs $ \ebs -> f (eb:ebs)+enrollList (b:bs) f = enroll b $ \eb -> enrollList bs $ f . (eb:) -- | 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)
Control/Concurrent/CHP/Event.hs view
@@ -31,7 +31,11 @@ module Control.Concurrent.CHP.Event (RecordedEventType(..), Event, getEventUnique, SignalVar, SignalValue(..), enableEvents, disableEvents, newEvent, newEventUnique, enrollEvent, resignEvent, poisonEvent, checkEventForPoison,- testAll, getEventTypeVal) where+ getEventTypeVal+#ifdef CHP_TEST+ , testAll+#endif+ ) where import Control.Arrow import Control.Concurrent.STM@@ -44,8 +48,9 @@ import qualified Data.Traversable as T import Data.Unique import Prelude hiding (seq)+#ifdef CHP_TEST import Test.HUnit hiding (test)-+#endif import Control.Concurrent.CHP.Poison import Control.Concurrent.CHP.ProcessId@@ -364,8 +369,8 @@ -- one: (if Map.size (unionAll otherEvents) == 1 then next- else (next ++ zip (repeat $ return ())- (Map.keys $ unionAll otherEvents)))+ else next ++ zip (repeat $ return ())+ (Map.keys $ unionAll otherEvents)) else -- No way it could be ready, so ignore it: discoverRelatedOffersAll a next @@ -427,7 +432,7 @@ PoisonItem -> return PoisonItem NoPoison (count, seq, offers) -> do writeTVar (getEventTVar e) $ NoPoison (count - 1, seq, offers)- if (count - 1 == length offers)+ if count - 1 == length offers then liftM (fmap $ \mu -> [((r,u),pids) | (u,(r,pids)) <- Map.toList mu]) $ discoverAndResolve $ Right e else return $ NoPoison []@@ -558,11 +563,11 @@ -- Testing: ---------------------------------------------------------------------- -----------------------------------------------------------------------+#ifdef CHP_TEST -- Tests if two lists have the same elements, but not necessarily in the same order: (**==**) :: Eq a => [a] -> [a] -> Bool-a **==** b = (length a == length b) && (null $ a \\ b)+a **==** b = (length a == length b) && null (a \\ b) (**/=**) :: Eq a => [a] -> [a] -> Bool a **/=** b = not $ a **==** b@@ -655,7 +660,7 @@ {- Offers: -} [ [(Bool, [Int]) {- events -}]] -> {-Starting events:-} [Int] -> IO () test testName eventCounts offerSets startEvents = do (events, realOffers) <- makeTestEvents (map fst eventCounts) (map (map snd) offerSets)- let expectedResult' = NoPoison $+ let expectedResult' = NoPoison ([OfferSet (tv,pid,[off | (m,off) <- zip [0..] offs, fst $ offerSets !! n !! m]) | (n,OfferSet (tv,pid,offs)) <- zip [0..] realOffers] ,Set.fromList [events !! n@@ -854,4 +859,8 @@ | (n,(NoPoison count, st)) <- zip [0..] eventCounts] uncurry (assertEqual testName) (unzip $ catMaybes c) - showStuff = show . fmap (map (\(u,x) -> (hashUnique u, x)) . Map.toList)+ showStuff = show . fmap (map (first hashUnique) . Map.toList)++#endif+-- CHP_TEST+
Control/Concurrent/CHP/Guard.hs view
@@ -30,6 +30,7 @@ module Control.Concurrent.CHP.Guard where import Control.Concurrent.STM+import Control.Monad import Control.Monad.Trans import qualified Data.Map as Map import Data.Monoid@@ -78,8 +79,7 @@ = TimeoutGuard $ do signalDone <- liftIO $ registerDelay n return $ do b <- readTVar signalDone- if b == False- then retry- else return ()+ when (not b) retry+
Control/Concurrent/CHP/Monad.hs view
@@ -36,9 +36,6 @@ onPoisonTrap, onPoisonRethrow, throwPoison, Poisonable(..), poisonAll, - -- * LoopWhileT Monad- LoopWhileT, loop, while,- -- * Primitive actions skip, stop, waitFor ) where@@ -92,48 +89,6 @@ -- | A convenient version of embedCHP1 that ignores the result embedCHP1_ :: (a -> CHP b) -> CHP (a -> IO ()) embedCHP1_ = liftM (\m x -> m x >> return ()) . embedCHP1----- | A monad transformer for easier looping. This is independent of the--- CHP aspects, but has all the right type-classes defined for it to make--- it easy to use with the CHP library.-newtype Monad m => LoopWhileT m a = LWT { getLoop :: m (Maybe a) }--instance Monad m => Monad (LoopWhileT m) where- -- m :: RW (Maybe (m a))- -- f :: a -> RW (Maybe (m b)) - m >>= f = LWT $ do x <- getLoop m- case x of- Nothing -> return Nothing- Just m' -> getLoop $ f m'- return x = LWT $ return $ Just x--instance MonadTrans LoopWhileT where- lift m = LWT $ m >>= return . Just--instance MonadIO m => MonadIO (LoopWhileT m) where- liftIO = lift . liftIO--instance MonadCHP m => MonadCHP (LoopWhileT m) where- liftCHP = lift . liftCHP---- | Runs the given action in a loop, executing it repeatedly until a 'while'--- statement inside it has a False condition. If you use 'loop' without 'while',--- the effect is the same as 'forever'.-loop :: Monad m => LoopWhileT m a -> m ()-loop l = do x <- getLoop l- case x of- Nothing -> return ()- Just _ -> loop l---- | Continues executing the loop if the given value is True. If the value--- is False, the loop is broken immediately, and control jumps back to the--- next action after the outer 'loop' statement. Thus you can build pre-condition,--- post-condition, and \"mid-condition\" loops, placing the condition wherever--- you like.-while :: Monad m => Bool -> LoopWhileT m ()-while b = LWT $ if b then (return $ Just ()) else return Nothing- -- | Waits for the specified number of microseconds (millionths of a second). -- There is no guaranteed precision, but the wait will never complete in less
Control/Concurrent/CHP/Mutex.hs view
@@ -35,7 +35,7 @@ type Mutex = MVar () claimMutex :: MonadIO m => Mutex -> m ()-claimMutex m = liftIO $ takeMVar m+claimMutex = liftIO . takeMVar newMutex :: MonadIO m => m Mutex newMutex = liftIO $ newMVar ()
Control/Concurrent/CHP/Parallel.hs view
@@ -179,6 +179,6 @@ r <- wrapProcess p $ flip runReaderT blank . pullOutStandard C.block $ atomically $ do (poisonedAlready, n) <- readTVar b- writeTVar b $ (poisonedAlready || isNothing r, n - 1)+ writeTVar b (poisonedAlready || isNothing r, n - 1) return ()
− Control/Concurrent/CHP/Test.hs
@@ -1,325 +0,0 @@--- Communicating Haskell Processes.--- Copyright (c) 2009, University of Kent.--- All rights reserved.--- --- Redistribution and use in source and binary forms, with or without--- modification, are permitted provided that the following conditions are--- met:------ * Redistributions of source code must retain the above copyright--- notice, this list of conditions and the following disclaimer.--- * Redistributions in binary form must reproduce the above copyright--- notice, this list of conditions and the following disclaimer in the--- documentation and/or other materials provided with the distribution.--- * Neither the name of the University of Kent nor the names of its--- contributors may be used to endorse or promote products derived from--- this software without specific prior written permission.------ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS--- IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,--- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR--- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR--- CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,--- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,--- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR--- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF--- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING--- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS--- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.---- | A module containing some useful functions for testing CHP programs, both in--- the QuickCheck 2 framework and using HUnit.------ This whole module was added in version 1.4.0.-module Control.Concurrent.CHP.Test (QuickCheckCHP, qcCHP, qcCHP', propCHPInOut, testCHP, testCHPInOut,- testCHP', CHPTestResult(..), (=*=), CHPTest, withCheck, assertCHP, assertCHP',- assertCHPEqual, assertCHPEqual') where--import Control.Arrow-import Control.Monad-import Control.Monad.Error (ErrorT, runErrorT, throwError)-import Control.Monad.Trans (MonadIO)-import Data.Maybe-import Data.Monoid-import Data.Unique-import Test.HUnit (assertFailure, Test(..))-import Test.QuickCheck (Gen, forAll)-import Test.QuickCheck.Property (Property, Result(..), Testable(..), failed, succeeded, liftIOResult)-import Text.PrettyPrint.HughesPJ--import Control.Concurrent.CHP-import Control.Concurrent.CHP.Traces---- | A wrapper around the CHP type that supports some QuickCheck 'Testable' instances.--- See 'qcCHP' and 'qcCHP''.------ Added in version 1.5.0.-newtype QuickCheckCHP a = QCCHP (IO (Maybe a, Doc))---- | Turns a CHP program into a 'QuickCheckCHP' for use with 'Testable' instances.------ Equivalent to @qcCHP' . runCHP_CSPTrace@.------ Added in version 1.5.0.-qcCHP :: CHP a -> QuickCheckCHP a-qcCHP = qcCHP' . runCHP_CSPTrace---- | Takes the command that runs a CHP program and gives back a 'QuickCheckCHP'--- item for use with 'Testable' instances.------ You use this function like:------ > qcCHP' (runCHP_CSPTrace p)------ To test process @p@ with a CSP trace if it fails. To turn off the display of--- tracing when a test fails, use:------ > qcCHP' (runCHP_TraceOff p)------ Added in version 1.5.0.-qcCHP' :: Trace t => IO (Maybe a, t Unique) -> QuickCheckCHP a-qcCHP' = QCCHP . liftM (second prettyPrint)--qcResult :: IO (Maybe Result, Doc) -> Property-qcResult m = liftIOResult $- do (mr, t) <- m- case mr of- Just r -> return $ r { reason = reason r ++ "; trace: " ++ show t }- Nothing -> return $ failed { reason = "QuickCheckCHP Failure (deadlock/uncaught poison); trace: " ++ show t }--chpToQC :: CHPTestResult -> Result-chpToQC (CHPTestPass) = succeeded-chpToQC (CHPTestFail msg) = failed { reason = msg }--boolToResult :: Bool -> Result-boolToResult b = if b then succeeded else failed--instance Testable (QuickCheckCHP Bool) where- property (QCCHP x) = qcResult $ liftM (first $ fmap boolToResult) x--instance Testable (QuickCheckCHP Result) where- property (QCCHP x) = qcResult x--instance Testable (QuickCheckCHP CHPTestResult) where- property (QCCHP x) = qcResult $ liftM (first $ fmap chpToQC) x------ | Tests a process that takes a single input and produces a single output, using--- QuickCheck.------ The first parameter is a pure function that takes the input to the process,--- the output the process gave back, and indicates whether this is okay (True =--- test pass, False = test fail). The second parameter is the process to test,--- and the third parameter is the thing to use to generate the inputs (passing 'arbitrary'--- is the simplest thing to do).------ Here are a couple of example uses:--- --- > propCHPInOut (==) Common.id (arbitrary :: Gen Int)--- --- > propCHPInOut (const $ (< 0)) (Common.map (negate . abs)) (arbitrary :: Gen Int)------ The test starts the process afresh each time, and shuts it down after the single--- output has been produced (by poisoning both its channels). Any poison from--- the process being tested after it has produced its output is consequently ignored,--- but poison instead of producing an output will cause a test failure.--- If the process does not produce an output or poison (for example if you test--- something like the Common.filter process), the test will deadlock.-propCHPInOut :: Show a => (a -> b -> Bool) -> (Chanin a -> Chanout b -> CHP ()) -> Gen a -> Property-propCHPInOut f p gen- = forAll gen $ \x -> qcCHP $- do c <- oneToOneChannel- d <- oneToOneChannel- (_,r) <- (p (reader c) (writer d)- `onPoisonTrap` (poison (reader c) >> poison (writer d)))- <||> ((do writeChannel (writer c) x- y <- readChannel (reader d)- poison (writer c) >> poison (reader d)- return $ f x y- ) `onPoisonTrap` return False)- return r---- | Takes a CHP program that returns a Bool (True = test passed, False = test--- failed) and forms it into an HUnit test.------ Note that if the program exits with poison, this is counted as a test failure.-testCHP :: CHP Bool -> Test-testCHP = TestCase . (>>= assertWithTrace) . runCHPAndTrace- where- assertWithTrace :: (Maybe Bool, CSPTrace Unique) -> IO ()- assertWithTrace (Just True, _) = return ()- assertWithTrace (Just False, t) = assertFailure $ "testCHP Failure; trace: " ++ show (prettyPrint t)- assertWithTrace (Nothing, t) = assertFailure $ "testCHP Failure (deadlock/uncaught poison); trace: " ++ show (prettyPrint t)---- | A helper type for describing a more detailed result of a CHP test. You can--- construct these values manually, or using the '(=*=)' operator.------ Added in version 1.5.0.-data CHPTestResult = CHPTestPass | CHPTestFail String--instance Monoid CHPTestResult where- mempty = CHPTestPass- mappend CHPTestPass y = y- mappend x _ = x---- | Checks if two things are equal; passes the test if they are, otherwise fails--- and gives an error that shows the two things in question.------ Added in version 1.5.0.-(=*=) :: (Eq a, Show a) => a -> a -> CHPTestResult-(=*=) expected act- | expected == act = CHPTestPass- | otherwise = CHPTestFail $ "Expected: " ++ show expected ++ "; Actual: " ++ show act---- | Like 'testCHP' but allows you to return the more descriptive 'CHPTestResult'--- type, rather than a plain Bool.------ Added in version 1.5.0.-testCHP' :: CHP CHPTestResult -> Test-testCHP' p = TestCase $ do (r, t) <- runCHP_CSPTrace p- case r of- Just CHPTestPass -> return ()- Just (CHPTestFail s) -> assertFailure $- s ++ "; trace: " ++ show t- Nothing -> assertFailure $ "testCHP' Failure (deadlock/uncaught poison); trace: "- ++ show t---- | See withCheck. Added in version 1.5.0.-newtype CHPTest a = CHPTest (ErrorT String CHP a)- deriving (Monad, MonadIO, MonadCHP)---- | A helper function that allows you to create CHP tests in an assertion style, either--- for use with HUnit or QuickCheck 2.------ Any poison thrown by the first argument (the left-hand side when this function--- is used infix) is trapped and ignored. Poison thrown by the second argument--- (the right-hand side when used infix) is counted as a test failure.------ As an example, imagine that you have a process that should repeatedly--- output the same value (42), called @myProc@. There are several ways to test--- this, but for the purposes of illustration we will start by testing the--- first two values:------ > myTest :: Test--- > myTest = testCHP' $ do--- > c <- oneToOneChannel--- > myProc (writer c)--- > `withCheck` do x0 <- liftCHP $ readChannel (reader c)--- > assertCHPEqual (poison (reader c)) "First value" 42 x0--- > x1 <- liftCHP $ readChannel (reader c)--- > poison (reader c) -- Shutdown myProc--- > assertCHPEqual' "Second value" 42 x1------ This demonstrates the typical pattern: a do block with some initialisation to--- begin with (creating channels, enrolling on barriers), then a withCheck call--- with the thing you want to test on the left-hand side, and the part doing the--- testing with the asserts on the right-hand side. Most CHP actions must be surrounded--- by 'liftCHP', and assertions can then be made about the values.------ Poison is used twice in our example. The assertCHPEqual function takes as a--- first argument the command to execute if the assertion fails. The problem--- is that if the assertion fails, the right-hand side will finish. But it is--- composed in parallel with the left-hand side, which does not know to finish--- (deadlock!). Thus we must pass a command to execute if the assertion fails--- that will shutdown the right-hand side. The second assertion doesn't need--- this, because by the time we make the assertion, we have already inserted--- the poison. Don't forget that you must poison to shut down the left-hand--- side if your test is successful or else you will again get deadlock.------ A better way to test this process is of course to read in a much larger number--- of samples and check they are all the same, for example:------ > myTest :: Test--- > myTest = testCHP' $ do--- > c <- oneToOneChannel--- > myProc (writer c)--- > `withCheck` do xs <- liftCHP $ replicateM 1000 $ readChannel (reader c)--- > poison (reader c) -- Shutdown myProc--- > assertCHPEqual' "1000 values" xs (replicate 1000 42)------ Added in version 1.5.0.-withCheck :: CHP a -> CHPTest () -> CHP CHPTestResult-withCheck p (CHPTest t) = liftM snd $ (p `onPoisonTrap` return undefined) <||> do- er <- runErrorT t- case er of- Left msg -> return $ CHPTestFail msg- Right _ -> return CHPTestPass---- | Checks that the given Bool is True. If it is, the assertion passes and the--- test continues. If it is False, the given command is run (which should shut--- down the left-hand side of withCheck) and the test finishes, failing with the--- given String.------ Added in version 1.5.0.-assertCHP :: CHP () -> String -> Bool -> CHPTest ()-assertCHP comp msg passed- | passed = return ()- | otherwise = liftCHP comp >> CHPTest (throwError msg)---- | Checks that the given values are equal (first is the expected value of the--- test, second is the actual value). If they are equal, the assertion passes and the--- test continues. If they are not equal, the given command is run (which should shut--- down the left-hand side of withCheck) and the test finishes, failing with the--- a message formed of the given String, and describing the two values.------ Added in version 1.5.0.-assertCHPEqual :: (Eq a, Show a) => CHP () -> String -> a -> a -> CHPTest ()-assertCHPEqual comp msg expected act- = assertCHP comp- (msg ++ "; expected: " ++ show expected ++ "; actual: " ++ show act)- (expected == act)---- | Like 'assertCHP' but issues no shutdown command. You should only use this--- function if you are sure that the left-hand side of withCheck has already completed.------ Added in version 1.5.0.-assertCHP' :: String -> Bool -> CHPTest ()-assertCHP' = assertCHP (return ())---- | Like 'assertCHPEqual' but issues no shutdown command. You should only use this--- function if you are sure that the left-hand side of withCheck has already completed.------ Added in version 1.5.0.-assertCHPEqual' :: (Eq a, Show a) => String -> a -> a -> CHPTest ()-assertCHPEqual' = assertCHPEqual (return ())---- | Tests a process that takes a single input and produces a single output, using--- HUnit.------ The first parameter is a pure function that takes the input to the process,--- the output the process gave back, and indicates whether this is okay (True =--- test pass, False = test fail). The second parameter is the process to test,--- and the third parameter is the input to send to the process.------ The intention is that you will either create several tests with the same first--- two parameters or use a const function as the first parameter. So for example,--- here is how you might test the identity process with several tests:--- --- > let check = testCHPInOut (==) Common.id--- > in TestList [check 0, check 3, check undefined]------ Whereas here is how you could test a slightly different process:------ > let check = testCHPInOut (const $ (< 0)) (Common.map (negate . abs))--- > in TestList $ map check [-5..5]------ The test starts the process afresh each time, and shuts it down after the single--- output has been produced (by poisoning both its channels). Any poison from--- the process being tested after it has produced its output is consequently ignored,--- but poison instead of producing an output will cause a test failure.--- If the process does not produce an output or poison (for example if you test--- something like the Common.filter process), the test will deadlock.-testCHPInOut :: (a -> b -> Bool) -> (Chanin a -> Chanout b -> CHP ()) -> a -> Test-testCHPInOut f p x- = testCHP $ do c <- oneToOneChannel- d <- oneToOneChannel- liftM snd $ (p (reader c) (writer d)- `onPoisonTrap` (poison (reader c) >> poison (writer d)))- <||> ((do writeChannel (writer c) x- y <- readChannel (reader d)- poison (writer c) >> poison (reader d)- return $ f x y- ) `onPoisonTrap` return False)--
Control/Concurrent/CHP/Traces.hs view
@@ -151,7 +151,7 @@ | otherwise = c makeCont (StructuralSequence 0 _) _ = ContDone makeCont (StructuralSequence n es) pid- = mconcat (map (uncurry makeCont) $ zip es pidsPlusOne)+ = mconcat (zipWith makeCont es pidsPlusOne) `mappend` makeCont (StructuralSequence (n-1) es) (last pidsPlusOne) where pidsPlusOne = take (1 + length es) $ iterate incPid pid@@ -160,7 +160,7 @@ where ParSeq p s = last ps makeCont (StructuralParallel es) pid- = mergePar (map (uncurry makeCont) $ zip es (parPids pid))+ = mergePar (zipWith makeCont es (parPids pid)) where parPids (ProcessId ps) = [ProcessId $ ps ++ [ParSeq i 0] | i <- [0..]]
Control/Concurrent/CHP/Traces/Base.hs view
@@ -115,8 +115,8 @@ nameEvent (t, c) = liftM (++ suffix) $ getName prefix c where (prefix, suffix) = case t of- ChannelComm x -> ("_c", if null x then "" else "." ++ x)- BarrierSync x -> ("_b", if null x then "" else "." ++ x)+ ChannelComm x -> ("_c", if null x then "" else '.' : x)+ BarrierSync x -> ("_b", if null x then "" else '.' : x) ClockSync st -> ("_t", ':' : st) nameEvent' :: Ord u => RecordedEvent u -> State (Map.Map u String) (RecordedEvent String)@@ -205,10 +205,10 @@ -- | Records an event where you were one of the people involved recordEvent :: [RecordedIndivEvent Unique] -> TraceT IO ()-recordEvent e = ask >>= lift . mapSubTrace rec+recordEvent e = ask >>= lift . mapSubTrace recH where- rec (Hierarchy es) = modifyIORef es (addParEventsH (map StrEvent e))- rec _ = return ()+ recH (Hierarchy es) = modifyIORef es (addParEventsH (map StrEvent e))+ recH _ = return () mergeSubProcessTraces :: [TraceStore] -> TraceT IO () mergeSubProcessTraces ts@@ -278,8 +278,7 @@ labelEvent :: Event -> String -> TraceT IO ()-labelEvent e l- = labelUnique (getEventUnique e) l+labelEvent e = labelUnique (getEventUnique e) labelUnique :: Unique -> String -> TraceT IO () labelUnique u l
Control/Concurrent/CHP/Traces/CSP.hs view
@@ -54,7 +54,7 @@ runCHPProgramWith' st (flip toPublic st) p prettyPrint (CSPTrace (labels, events))- = char '<' <+> (sep $ punctuate (char ',') $ evalState (mapM (liftM text . nameEvent) events) labels) <+> char '>'+ = char '<' <+> sep (punctuate (char ',') $ evalState (mapM (liftM text . nameEvent) events) labels) <+> char '>' labelAll (CSPTrace (labels, events)) = CSPTrace (Map.empty, evalState (mapM nameEvent' events) labels)@@ -79,6 +79,6 @@ runCHP_CSPTraceAndPrint :: CHP a -> IO () runCHP_CSPTraceAndPrint p = do (_, tr) <- runCHP_CSPTrace p- putStrLn $ show $ tr+ putStrLn $ show tr
Control/Concurrent/CHP/Traces/Structural.hs view
@@ -122,7 +122,7 @@ pp (StructuralSequence 1 es) = sep $ intersperse (text "->") $ map pp es pp (StructuralSequence n es)- = int n <> char '*' <> (parens $ sep $+ = int n <> char '*' <> parens (sep $ intersperse (text "->") $ map pp es) pp (StructuralParallel es) = parens $ sep $ intersperse (text "||") $ map pp es
Control/Concurrent/CHP/Traces/VCR.hs view
@@ -61,7 +61,7 @@ runCHPProgramWith' st (flip toPublic st) p prettyPrint (VCRTrace (labels, eventSets))- = char '<' <+> (sep $ punctuate (char ',') $ map (braces . sep . punctuate (char ',')) ropes) <+> char '>'+ = char '<' <+> sep (punctuate (char ',') $ map (braces . sep . punctuate (char ',')) ropes) <+> char '>' where es = evalState (mapM nameVCR eventSets) labels
− Control/Concurrent/CHP/Utils.hs
@@ -1,267 +0,0 @@--- Communicating Haskell Processes.--- Copyright (c) 2008--2009, University of Kent.--- All rights reserved.--- --- Redistribution and use in source and binary forms, with or without--- modification, are permitted provided that the following conditions are--- met:------ * Redistributions of source code must retain the above copyright--- notice, this list of conditions and the following disclaimer.--- * Redistributions in binary form must reproduce the above copyright--- notice, this list of conditions and the following disclaimer in the--- documentation and/or other materials provided with the distribution.--- * Neither the name of the University of Kent nor the names of its--- contributors may be used to endorse or promote products derived from--- this software without specific prior written permission.------ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS--- IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,--- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR--- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR--- CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,--- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,--- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR--- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF--- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING--- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS--- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.---- | A collection of useful functions to use with the library.------ The most useful operation is 'pipeline' which you can use to wire up a list--- of processes into a line, and run them. The corresponding '|->|' operator is--- a simple binary version that can be a little more concise. When the pipeline--- has channels going in both directions rather than just one, 'dualPipeline' and/or--- '|<->|' can be used. Several other variants on these functions are also provided,--- including operators to use at the beginning and ends of pipelines.------ Most of the functions in this module are superseded or generalised by those--- in the "Control.Concurrent.CHP.Connect" module since version 1.7.0, so you should--- look to use those connectors rather than these, as the connects in this module--- may be removed at some point in the future.-module Control.Concurrent.CHP.Utils where--import Control.Monad--import Control.Concurrent.CHP---- | Wires given processes up in a forward cycle. That is, the first process--- writes to the second, and receives from the last. It returns the list of--- wired-up processes, which you will almost certainly want to run in parallel.-wireCycle :: Channel r w => [r a -> w a -> proc] -> CHP [proc]-wireCycle procs- = do chan <- newChannel- wirePipeline procs (reader chan) (writer chan)- -- return [p (reader $ chans !! i) (writer $ chans !! ((i + 1) `mod` n)) | (p, i) <- zip procs [0..]]---- | Like wireCycle, but works with processes that connect with a channel in both--- directions.------ This function was added in version 1.4.0.-wireDualCycle :: (Channel r w, Channel r' w') =>- [(r a, w' b) -> (r' b, w a) -> proc] -> CHP [proc]-wireDualCycle procs- = do c <- newChannel- d <- newChannel- wireDualPipeline procs (reader c, writer d) (reader d, writer c)---- | Wires the given processes up in a forward pipeline. The first process--- in the list is connected to the given reading channel-end (the first parameter)--- and the writing end of a new channel, A. The second process is wired up--- to the reading end of A, and the writing end of the next new channel, B.--- This proceeds all the way to the end of the list, until the final process--- is wired to the reading end of Z (if you have 27 processes in the list,--- and therefore 26 channels in the middle of them) and the second parameter.--- The list of wired-up processes is returned, which you can then run in parallel.-wirePipeline :: forall a r w proc. Channel r w => [r a -> w a -> proc] -> r a -> w a- -> CHP [proc]-wirePipeline [] _ _ = return []-wirePipeline procs in_ out- = do chans <- replicateM (n - 1) newChannel- -- return $ map (wire chans) $ zip procs [0..]- return $ (\(w, ps) -> head procs in_ w : ps) $ (foldr wireF (out, []) $ zip (tail procs) chans)- where- n = length procs-- -- One way of doing it:- {-- wire :: [OneToOneChannel a] -> (Chanin a -> Chanout a -> CSProcess, Int) -> CSProcess- wire cs (p, i)- | i == 0 = p in_ (writer $ cs !! 0)- | i == n - 1 = p (reader $ cs !! i) out- | otherwise = p (reader $ cs !! i) (writer $ cs !! (i + 1))- -}- -- A way without indexing (possibly a bit more efficient):- wireF :: (r a -> w a -> proc, Chan r w a) -> (w a, [proc]) -> (w a, [proc])- wireF (p, c) (w, ps) = (writer c, p (reader c) w : ps)---- | Like wirePipeline, but works with processes that connect with a channel in both--- directions.------ This function was added in version 1.4.0.-wireDualPipeline :: forall a b r w r' w' proc. (Channel r w, Channel r' w') =>- [(r a, w' b) -> (r' b, w a) -> proc] -> (r a, w' b) -> (r' b, w a) -> CHP [proc]-wireDualPipeline [] _ _ = return []-wireDualPipeline procs@(first:rest) in_ out- = do chans <- replicateM (n - 1) newChannel- chans' <- replicateM (n - 1) newChannel- return $ (\(w, ps) -> first in_ w : ps)- $ (foldr wireF (out, []) $ zip3 rest chans chans')- where- n = length procs-- wireF :: ((r a, w' b) -> (r' b, w a) -> proc, Chan r w a, Chan r' w' b)- -> ((r' b, w a), [proc]) -> ((r' b, w a), [proc])- wireF (p, c, d) (w, ps) = ((reader d, writer c), p (reader c, writer d) w : ps)---- | A specialised version of 'wirePipeline'. Given a list of processes, composes--- them into an ordered pipeline, that takes the channel-ends for the sticking--- out ends of the pipeline and gives a process that returns a list of their--- results. This is equivalent to 'wirePipeline', with the return value fed--- to 'runParallel'.------ Added in version 1.0.2.-pipeline :: [Chanin a -> Chanout a -> CHP b] -> Chanin a -> Chanout a -> CHP [b]-pipeline procs in_ out = wirePipeline procs in_ out >>= runParallel---- | Like pipeline, but works with processes that connect with a channel in both--- directions.------ This function was added in version 1.4.0.-dualPipeline :: [(Chanin a, Chanout b) -> (Chanin b, Chanout a) -> CHP c]- -> (Chanin a, Chanout b) -> (Chanin b, Chanout a) -> CHP [c]-dualPipeline p i o = wireDualPipeline p i o >>= runParallel---- | A specialised version of 'wireCycle'. Given a list of processes, composes--- them into a cycle and runs them all in parallel. This is equivalent to--- 'wireCycle' with the return value fed into 'runParallel'.------ Added in version 1.0.2.-cycle :: [Chanin a -> Chanout a -> CHP b] -> CHP [b]-cycle procs = wireCycle procs >>= runParallel---- | Like cycle, but works with processes that connect with a channel in both--- directions.------ This function was added in version 1.4.0.-dualCycle :: [(Chanin a, Chanout b) -> (Chanin b, Chanout a) -> CHP c]- -> CHP [c]-dualCycle p = wireDualCycle p >>= runParallel----- | Process composition. Given two processes, composes them into a pipeline,--- like function composition (but with an opposite ordering). The function--- is associative. Using wirePipeline will be more efficient than @foldl1--- (|->|)@ for more than two processes.------ The type for this process became more specific in version 1.2.0.-(|->|) :: (a -> Chanout b -> CHP ()) -> (Chanin b -> c -> CHP ()) ->- (a -> c -> CHP ())-(|->|) p q x y = do c <- oneToOneChannel- runParallel_ [p x (writer c), q (reader c) y]---- | Like (|->|), but labels the channel and uses show for the traces.------ Added in version 1.5.0.-(|->|^) :: Show b => (a -> Chanout b -> CHP ()) -> (String, Chanin b -> c -> CHP ()) ->- (a -> c -> CHP ())-(|->|^) p (l, q) x y- = do c <- oneToOneChannel' $ chanLabel l- runParallel_ [p x (writer c), q (reader c) y]---- | Process composition that works with processes that connect with a channel in both--- directions. Like (|->|), but connects a channel in each direction.------ This function was added in version 1.4.0.--(|<->|) :: (a -> (Chanin b, Chanout c) -> CHP ())- -> ((Chanin c, Chanout b) -> d -> CHP ())- -> (a -> d -> CHP ())-(|<->|) p q x y = do c <- oneToOneChannel- d <- oneToOneChannel- runParallel_ [p x (reader d, writer c), q (reader c, writer d) y]---- | The reversed version of the other operator.------ The type for this process became more specific in version 1.2.0.-(|<-|) :: (Chanin b -> c -> CHP ()) -> (a -> Chanout b -> CHP ()) ->- (a -> c -> CHP ())-(|<-|) = flip (|->|)---- | A function to use at the start of a pipeline you are chaining together with--- the '|->|' operator.--- Added in version 1.2.0.-(->|) :: (Chanout b -> CHP ()) -> (Chanin b -> c -> CHP ())- -> (c -> CHP ())-(->|) p q x = do c <- oneToOneChannel- runParallel_ [p (writer c), q (reader c) x]---- | A function to use at the end of a pipeline you are chaining together with--- the '|->|' operator.--- Added in version 1.2.0.-(|->) :: (a -> Chanout b -> CHP ()) -> (Chanin b -> CHP ())- -> (a -> CHP ())-(|->) p q x = do c <- oneToOneChannel- runParallel_ [p x (writer c), q (reader c)]---- | A function to use at the start of a pipeline you are chaining together with--- the '|<->|' operator.--- Added in version 1.4.0.-(|<->) :: (a -> (Chanin b, Chanout c) -> CHP ()) -> ((Chanin c, Chanout b) -> CHP ())- -> (a -> CHP ())-(|<->) p q x = do c <- oneToOneChannel- d <- oneToOneChannel- runParallel_ [p x (reader d, writer c), q (reader c, writer d)]---- | A function to use at the end of a pipeline you are chaining together with--- the '|<->|' operator.--- Added in version 1.4.0.-(<->|) :: ((Chanin b, Chanout c) -> CHP ()) -> ((Chanin c, Chanout b) -> a -> CHP ())- -> (a -> CHP ())-(<->|) p q x = do c <- oneToOneChannel- d <- oneToOneChannel- runParallel_ [p (reader d, writer c), q (reader c, writer d) x]--{---- Like runParallel, but offers a choice between the leading event of each--- parallel branch such that if any leading event of a parallel branch is--- poisoned, any siblings still waiting for their leading event will also be--- poisoned. Note however that any handlers in the sibling branches will not--- execute, as technically they did not encounter poison.------ If all the branches have just one event (e.g. a readChannel), this ensures that--- the parallel composition will not deadlock in the presence of poison.------ Added in version 1.5.0.-runParallelPoison :: [CHP a] -> CHP [a]-runParallelPoison ps- = do b <- newBarrierWithLabel "runParallelPoison"- -- The barrier can never sync properly, but it can be poisoned:- enroll b $ const $ enrollList (replicate (length ps) b) $- \ebs -> runParallel $ zipWith useBar ebs ps- where- useBar :: EnrolledBarrier -> CHP a -> CHP a- useBar b p = (p <-> (syncBarrier b >> throwPoison)) `onPoisonRethrow` (poison b)---- Like runParallel_, but offers a choice between the leading event of each--- parallel branch such that if any leading event of a parallel branch is--- poisoned, any siblings still waiting for their leading event will also be--- poisoned. Note however that any handlers in the sibling branches will not--- execute, as technically they did not encounter poison.------ If all the branches have just one event (e.g. a readChannel), this ensures that--- the parallel composition will not deadlock in the presence of poison.------ Added in version 1.5.0.-runParallelPoison_ :: [CHP a] -> CHP ()-runParallelPoison_ ps- = do b <- newBarrierWithLabel "runParallelPoison"- -- The barrier can never sync properly, but it can be poisoned:- enroll b $ const $ enrollList (replicate (length ps) b) $- \ebs -> runParallel_ $ zipWith useBar ebs ps- where- useBar :: EnrolledBarrier -> CHP a -> CHP a- useBar b p = (p <-> (syncBarrier b >> throwPoison)) `onPoisonRethrow` (poison b)--}-
chp.cabal view
@@ -1,13 +1,13 @@ Name: chp-Version: 1.8.0+Version: 2.0.0 Synopsis: An implementation of concurrency ideas from Communicating Sequential Processes License: BSD3 License-file: LICENSE Author: Neil Brown Maintainer: neil@twistedsquare.com-Copyright: Copyright (c) 2008--2009, University of Kent+Copyright: Copyright (c) 2008--2010, University of Kent Stability: Stable-Tested-with: GHC==6.8.2, GHC==6.10.1+Tested-with: GHC==6.10.4, GHC==6.12.1 Description: The Communicating Haskell Processes (CHP) library is an implementation of message-passing concurrency ideas from Hoare's Communicating Sequential Processes. More details and@@ -15,22 +15,19 @@ <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.+ 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. Homepage: http://www.cs.kent.ac.uk/projects/ofa/chp/ Category: Concurrency Cabal-Version: >= 1.2.3 Build-Type: Simple-Build-Depends: base >= 3 && < 5, extensible-exceptions >= 0.1.1.0, containers, HUnit, mtl, parallel >= 1 && < 2, pretty, QuickCheck >= 2, stm+Build-Depends: base >= 3 && < 5, containers, deepseq >= 1.1 && < 1.2, extensible-exceptions >= 0.1.1.0, loop-while, mtl, pretty, stm Exposed-modules: Control.Concurrent.CHP- Control.Concurrent.CHP.Actions Control.Concurrent.CHP.Alt- Control.Concurrent.CHP.Arrow Control.Concurrent.CHP.Barriers- Control.Concurrent.CHP.Behaviours- Control.Concurrent.CHP.BroadcastChannels- Control.Concurrent.CHP.Buffers Control.Concurrent.CHP.Channels Control.Concurrent.CHP.Channels.BroadcastReduce Control.Concurrent.CHP.Channels.Communication@@ -38,20 +35,14 @@ Control.Concurrent.CHP.Channels.Ends Control.Concurrent.CHP.Channels.Synonyms Control.Concurrent.CHP.Clocks- Control.Concurrent.CHP.Common- Control.Concurrent.CHP.Connect- Control.Concurrent.CHP.Connect.TwoDim- Control.Concurrent.CHP.Console Control.Concurrent.CHP.Enroll Control.Concurrent.CHP.Monad Control.Concurrent.CHP.Parallel- Control.Concurrent.CHP.Test Control.Concurrent.CHP.Traces Control.Concurrent.CHP.Traces.CSP Control.Concurrent.CHP.Traces.Structural Control.Concurrent.CHP.Traces.TraceOff Control.Concurrent.CHP.Traces.VCR- Control.Concurrent.CHP.Utils Other-modules: Control.Concurrent.CHP.Base Control.Concurrent.CHP.Channels.Base@@ -63,8 +54,7 @@ Control.Concurrent.CHP.ProcessId Control.Concurrent.CHP.Traces.Base -Extensions: ScopedTypeVariables MultiParamTypeClasses- FlexibleInstances TypeFamilies ParallelListComp- GeneralizedNewtypeDeriving CPP BangPatterns+Extensions: BangPatterns CPP FlexibleInstances GeneralizedNewtypeDeriving+ MultiParamTypeClasses ScopedTypeVariables GHC-Options: -Wall -auto-all