simple-actors 0.1.0 → 0.2.0
raw patch · 3 files changed
+81/−44 lines, 3 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Control.Concurrent.Actors: printB :: (Show s, Num n) => n -> Behavior s
+ Control.Concurrent.Actors: printB :: (Show s, Eq n, Num n) => n -> Behavior s
- Control.Concurrent.Actors: putStrB :: Num n => n -> Behavior String
+ Control.Concurrent.Actors: putStrB :: (Eq n, Num n) => n -> Behavior String
Files
- Control/Concurrent/Actors.lhs +73/−23
- Control/Concurrent/Actors/Behavior.lhs +1/−20
- simple-actors.cabal +7/−1
Control/Concurrent/Actors.lhs view
@@ -68,7 +68,30 @@ > -} > > -- * Actor Behaviors+> {- | +> In the Actor Model, at each step an actor...+> +> - processes a single 'received' message+> +> - may 'spawn' new actors+> +> - may 'send' messages to other actors+> +> - 'return's the 'Behavior' for processing the /next/ message+> +> These actions take place within the @Action i@ monad, where @i@ is the type+> of the input message the actor receives.+> +> /N.B.:/ the MonadIO instance here is an abstraction leak. An example of a+> good use of 'liftIO' might be to give an @Action@ access to a source of+> randomness.+> -} > Action()+> {- | +> An actor is created by 'spawn'ing a @Behavior@. Behaviors consist of a+> composed 'Action' that is executed when a message is 'received' and+> returns the @Behavior@ for processing the next input.+> -} > , Behavior(..) > -- ** Composing Behaviors > , (<.|>)@@ -83,11 +106,11 @@ > {- | > The 'spawn' function will be sufficient for forking actors in most cases, > but launching mutually-communicating actors presents a problem.-> .+> > In cases where a 'Behavior' needs access to its own 'Mailbox' or that of > an actor that must be forked later, the 'MonadFix' instance should be > used. GHC\'s \"Recursive Do\" make this especially easy:-> .+> > > {-# LANGUAGE DoRec #-} > > beh = Receive $ do > > i <- received@@ -99,7 +122,9 @@ > > send b3 i > > send "first" b2 > > yield+> > -}+> > , spawn > , spawn_ > , spawnReading@@ -107,7 +132,7 @@ > {- | > An actor computation can be halted immediately by calling 'yield', > a synonym for 'mzero'. When an 'Action' calling @yield@ is composed with-> another using @<|>@ the second takes over processing the /same/ input+> another using @\<|\>@ the second takes over processing the /same/ input > which the former @yield@-ed on. > > Here is an example of a computation using 'guard' which returns @mzero@ if@@ -129,6 +154,9 @@ > , receive > > -- * Utility functions+> {- | +> These are useful for debugging 'Behavior's+> -} > , runBehavior_ > , runBehavior >@@ -171,13 +199,22 @@ TODO ------- 0.2.0:+ 0.3.0:+ - define natural transformation combinators (in IO unfortunately) a.la.+ 'categories' for Mailbox. So+ - :: Mailbox (a,b) -> (Mailbox a, Mailbox b) -- divide?+ - :: Mailbox a -> Mailbox b -> Mailbox (Either a b) -- add?+ - etc...+ put these in a separate sub-module, optionally import, mention how an+ extension to actor model or something+ - allow supplying the first input message for an actor during spawn. This is+ awkward otherwise. Include in same sub-module as above? - performance testing: - take a look at threadscope for random tree test - get complete code coverage into simple test module- - interesting: http://en.wikipedia.org/wiki/Huang%27s_algorithm- - better method for waiting for threads to complete. should probbly use+ - interesting solution to exit detection: + http://en.wikipedia.org/wiki/Huang%27s_algorithm+ - better method for waiting for threads to complete. should probably use actor message passing - look into whether we should use Text lib instead of strings? OverloadedStrings?@@ -185,27 +222,39 @@ -test if this lets us use it in importing module w/ OverloadedStrings extension - structured declarative and unit tests- - Performance testing:- - test performance vs. straight Chans, etc.- - test out overhead of our various locks, especially difference if we- scrap the snederLockMutex - some sort of exception handling technique via Actors (look at enumerator package)- - investigate ways of positively influencing thread scheduling based on- actor work agenda - strict send' function- -Behavior -> enumeratee package translator (and vice versa)- (maybe letting us use useful enumerators)++Later:+ - investigate ways of positively influencing thread scheduling based on+ actor work agenda? - export some more useful Actors and global thingies - 'loop' which keeps consuming (is this provided by a class?) - function returning an actor to "load balance" inputs over multiple actors - an actor that sends a random stream? - a pre-declared Mailbox for IO?++ Eventualy: - provide an "adapter" for amazon SQS, allowing truly distributed message passing--+ - investigate erlang-style selective receive (using Alternative?)+ - consider: combining TChans, where values are popped off when available,+ for chan-split?+ - look at ways we can represent network IO as channels to interface with+ this. E.g:+ - https://github.com/ztellman/aleph+ - http://akka.io/ (scala remote actors lib)+ - http://www.zeromq.org/intro:read-the-manual+ - interface to amazon SQS+ - http://msgpack.org/ + - "shared memory" approaches?+ - cloudhaskell, haskell-mpi, etc. see: + http://stackoverflow.com/questions/8362998/distributed-haskell-state-of-the-art-in-2011+ -Behavior -> enumeratee package translator (and vice versa)+ (maybe letting us use useful enumerators)+ ...also now pipes, conduits, etc. etc. CHAN TYPES@@ -277,7 +326,9 @@ > -- > send out (b,a) > -- > return (pairUp out) > ---> -- Defined: @receive = return . Receive@+> -- Defined as: +> --+> -- > receive = return . Receive > receive :: Action i (Behavior i) -> Action i (Behavior i) > receive = return . Receive @@ -297,7 +348,7 @@ > -- | Send a message asynchronously. This can be used to send messages to other > -- Actors via a 'Mailbox', or used as a means of output from the Actor system > -- to IO since the function is polymorphic.-> -- .+> -- > -- > send b = liftIO . writeChan b > send :: (MonadIO m, SplitChan c x)=> c a -> a -> m () > send b = liftIO . writeChan b@@ -328,7 +379,6 @@ > runBehavior_ b = runBehavior b [(),()..] > > -- | run a 'Behavior' in the IO monad, taking its \"messages\" from the list.-> -- Useful for debugging @Behaviors@. > runBehavior :: Behavior a -> [a] -> IO () > runBehavior b (a:as) = runBehaviorStep b a >>= F.mapM_ (`runBehavior` as) > runBehavior _ _ = return ()@@ -360,7 +410,7 @@ > -- | Prints all messages to STDOUT in the order they are received, > -- 'yield'-ing /immediately/ after @n@ inputs are printed.-> printB :: (Show s, Num n)=> n -> Behavior s+> printB :: (Show s, Eq n, Num n)=> n -> Behavior s > printB = contramap (unlines . return . show) . putStrB We want to yield right after printing the last input to print. This lets us@@ -375,7 +425,7 @@ For now we allow negative > -- | Like 'printB' but using @putStr@.-> putStrB :: (Num n)=> n -> Behavior String+> putStrB :: (Eq n, Num n)=> n -> Behavior String > putStrB 0 = mempty --special case when called directly w/ 0 > putStrB n = Receive $ do > s <- received@@ -392,7 +442,7 @@ > -- | A @Behavior@ that discard its first input, returning the passed Behavior > -- for processing subsequent inputs. Useful with 'Alternative' or 'Monoid'-> -- compositions when one wants to ignore the leftover input.+> -- compositions when one wants to ignore the leftover 'yield'ed message. > -- > -- > constB = Receive . return > constB :: Behavior i -> Behavior i
Control/Concurrent/Actors/Behavior.lhs view
@@ -29,9 +29,6 @@ A Behavior wraps an Action i a, into a list-like sequence of actions to perform over inputs: -> -- | An actor is created by 'spawn'ing a @Behavior@. Behaviors consist of-> -- a composed 'Action' that is executed when a message is 'received' and-> -- returns the @Behavior@ for processing the next input. > newtype Behavior i = Receive { headAction :: Action i (Behavior i) } > > instance Contravariant Behavior where@@ -42,7 +39,7 @@ This is essentially a marriage of the Monoid [] instance with Action's Alternative instance, and I am mostly convinced it is right and has utility: -> -- | @b1 `mplus` b2@ has the 'headAction' of @b2@ begin where the 'abort'+> -- | @b1 `mplus` b2@ has the 'headAction' of @b2@ begin where the 'yield' > -- occured in @b1@, i.e. @b2@\'s first input will be the final input handed to > -- @b1@. > instance Monoid (Behavior i) where@@ -57,22 +54,6 @@ will be useful: -> -- | In the Actor Model, at each step an actor...-> ---> -- - processes a single 'received' message-> -- -> -- - may 'spawn' new actors-> -- -> -- - may 'send' messages to other actors-> -- -> -- - 'return's the 'Behavior' for processing the /next/ message-> ---> -- These actions take place within the @Action i@ monad, where @i@ is the type-> -- of the input message the actor receives.-> ---> -- /N.B.:/ the MonadIO instance here is an abstraction leak. An example of a-> -- good use of 'liftIO' might be to give an @Action@ access to a source of-> -- randomness. > newtype Action i a = Action { readerT :: ReaderT i (MaybeT IO) a } > deriving (Monad, MonadIO, MonadPlus, MonadReader i, > Functor, Applicative, Alternative, MonadFix)
simple-actors.cabal view
@@ -7,7 +7,7 @@ -- The package version. See the Haskell package versioning policy -- (http://www.haskell.org/haskellwiki/Package_versioning_policy) for -- standards guiding when and how versions should be incremented.-Version: 0.1.0+Version: 0.2.0 -- A short (one-line) description of the package. Synopsis: A library for more structured concurrent programming, based@@ -20,6 +20,12 @@ Model. Computations are structured as "Behaviors" which take a single input value, perform some 'Action's, and return the Behavior to process the next input message it receives.+ .+ /CHANGES/ 0.1 - 0.2:+ .+ - documentation cleanup+ .+ - updates for GHC 7.4.1 -- The license under which the package is released. License: BSD3