packages feed

Concurrential 0.4.0.0 → 0.5.0.0

raw patch · 2 files changed

+59/−95 lines, 2 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Control.Concurrent.Concurrential: instance Applicative m => Applicative (Concurrential m)
- Control.Concurrent.Concurrential: instance Applicative m => Monad (Concurrential m)
- Control.Concurrent.Concurrential: instance Functor m => Functor (Concurrential m)
- Control.Concurrent.Concurrential: runConcurrentialSimple :: Concurrential IO t -> (Async t -> IO r) -> IO r
- Control.Concurrent.Concurrential: type Joiner g = forall a. g (IO a) -> IO (g a)
- Control.Concurrent.Concurrential: type Runner f g = forall a. f a -> IO (g a)
+ Control.Concurrent.Concurrential: ConcurrentialAp :: Concurrential t -> ConcurrentialAp t
+ Control.Concurrent.Concurrential: concurrentially :: ConcurrentialAp t -> Concurrential t
+ Control.Concurrent.Concurrential: instance Applicative Concurrential
+ Control.Concurrent.Concurrential: instance Applicative ConcurrentialAp
+ Control.Concurrent.Concurrential: instance Functor Concurrential
+ Control.Concurrent.Concurrential: instance Functor ConcurrentialAp
+ Control.Concurrent.Concurrential: instance Monad Concurrential
+ Control.Concurrent.Concurrential: instance Typeable ConcurrentialAp
+ Control.Concurrent.Concurrential: instance Typeable SomeAsync
+ Control.Concurrent.Concurrential: newtype ConcurrentialAp t
- Control.Concurrent.Concurrential: concurrently :: m t -> Concurrential m t
+ Control.Concurrent.Concurrential: concurrently :: IO t -> ConcurrentialAp t
- Control.Concurrent.Concurrential: data Concurrential m t
+ Control.Concurrent.Concurrential: data Concurrential t
- Control.Concurrent.Concurrential: runConcurrential :: (Functor f, Applicative f, Monad f) => Joiner f -> Runner m f -> Concurrential m t -> (Async (f t) -> IO (f r)) -> IO (f r)
+ Control.Concurrent.Concurrential: runConcurrential :: Concurrential t -> (Async t -> IO r) -> IO r
- Control.Concurrent.Concurrential: sequentially :: m t -> Concurrential m t
+ Control.Concurrent.Concurrential: sequentially :: IO t -> ConcurrentialAp t

Files

Concurrential.cabal view
@@ -2,7 +2,7 @@ -- documentation, see http://haskell.org/cabal/users-guide/  name:                Concurrential-version:             0.4.0.0+version:             0.5.0.0 synopsis:            Mix concurrent and sequential computation -- description:          homepage:            http://github.com/avieth/Concurrential
Control/Concurrent/Concurrential.hs view
@@ -8,15 +8,19 @@ Portability : non-portable (GHC only)  The functions @sequentially@ and @concurrently@ inject @IO@ terms into the-@Concurrential@ monad. This monad's Applicative instance will exploit as-much concurrency as possible, much like the @Concurrently@ monad from async,-such that all @sequentially@ terms will be run in the order in which they-would have been run had they been typical IOs.+@ConcurrentialAp@ applicative functor, whose applicative instance will exploit+as much concurrency as possible such that all @sequentially@ terms will be run+in the order in which they would have been run had they been typical IOs.++Terms of @ConcurrentialAp@ can be transformed into terms of @Concurrential@,+which is a monad. The order of sequential terms is respected even through+binds; a sequential term will not be evaluted until all binds appearing+syntactically earlier than it have been expanded. -}  {-# LANGUAGE GADTs #-} {-# LANGUAGE RankNTypes #-}-{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE AutoDeriveTypeable #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE ScopedTypeVariables #-}@@ -24,15 +28,13 @@ module Control.Concurrent.Concurrential (      Concurrential--  , Runner-  , Joiner+  , ConcurrentialAp(ConcurrentialAp)    , runConcurrential-  , runConcurrentialSimple    , sequentially   , concurrently+  , concurrentially    , wait @@ -42,12 +44,12 @@ import Control.Monad import Control.Concurrent.MVar import Control.Concurrent.Async hiding (concurrently)-import Control.Exception-import Data.Typeable +-- | An Async without a type parameter, which can be waited for. data SomeAsync where   SomeAsync :: Async a -> SomeAsync +-- | Wait for a SomeAsync to complete. waitSomeAsync :: SomeAsync -> IO () waitSomeAsync (SomeAsync async) = wait async >> return () @@ -68,7 +70,6 @@ -- | Description of the way in which a monadic term's evaluation should be --   carried out. data Choice m t = Sequential (m t) | Concurrent (m t)-  deriving (Typeable)  instance Functor m => Functor (Choice m) where   fmap f choice = case choice of@@ -77,86 +78,65 @@  -- | Description of computation which is composed of sequential and concurrent --   parts in some monad @m@.-data Concurrential m t where-    SCAtom :: Choice m t -> Concurrential m t-    SCBind :: Concurrential m s -> (s -> Concurrential m t) -> Concurrential m t-    SCAp :: Concurrential m (r -> t) -> Concurrential m r -> Concurrential m t-  deriving (Typeable)+data Concurrential t where+    SCAtom :: Choice IO t -> Concurrential t+    SCBind :: Concurrential s -> (s -> Concurrential t) -> Concurrential t+    SCAp :: Concurrential (r -> t) -> Concurrential r -> Concurrential t -instance Functor m => Functor (Concurrential m) where+instance Functor Concurrential where   fmap f sc = case sc of     SCAtom choice -> SCAtom $ fmap f choice     SCBind sc k -> SCBind sc ((fmap . fmap) f k)     SCAp sf sx -> SCAp ((fmap . fmap) f sf) sx -instance Applicative m => Applicative (Concurrential m) where+instance Applicative Concurrential where   pure = SCAtom . Sequential . pure-  (<*>) = SCAp+  cf <*> cx = SCBind cf (\f -> SCBind cx (\x -> pure (f x))) -instance Applicative m => Monad (Concurrential m) where+instance Monad Concurrential where   return = pure   (>>=) = SCBind --- | This corresponds to the notion of a common type of monad transformer:---   there is some monad g, and then its associated transformer type f, for---   instance MaybeT = f and Maybe = g---   If we have an---   ---     @---       f m a---     @------   then we can get an------     @---       m (g a)---     @------   Here we're interested in the special case where we can achieve IO (g a).---   This does not mean we have to be dealing with an f IO a, it could mean---   that the IO is buried deeper in the transformer stack!------   Motivation: @Async@ functions work with @IO@ and only @IO@, but the @m@---   parameter of a Concurrential may be some other monad which is capable of---   performing @IO@, like @Either String IO@ for instance. In order to run---   computations in this moand through @Async@, we need to know how to get a---   hold of an @IO@. That's what the runner does.-type Runner f g = forall a . f a -> IO (g a)+-- | Concurrential without a Monad instance, but an Applicative instance+--   which exploits concurrency.+newtype ConcurrentialAp t = ConcurrentialAp {+    unConcurrentialAp :: Concurrential t+  } --- | A witness of this type proves that g is in some sense compatible with IO:---   we can bind through it.-type Joiner g = forall a . g (IO a) -> IO (g a)+instance Functor ConcurrentialAp where+  fmap f sc = ConcurrentialAp $ fmap f (unConcurrentialAp sc) +instance Applicative ConcurrentialAp where+  pure = ConcurrentialAp . pure+  cf <*> cx = ConcurrentialAp $ SCAp (unConcurrentialAp cf) (unConcurrentialAp cx)+ -- | Run a Concurrential term with a continuation. We choose CPS here because --   it allows us to explot @withAsync@, giving us a guarantee that an --   exception in a spawning thread will kill spawned threads. runConcurrentialK-  :: (Functor f, Applicative f, Monad f)-  => Joiner f-  -> Runner m f-  -> Concurrential m t+  :: Concurrential t   -- ^ The computation to run.   -> SomeAsync   -- ^ The sequential part.-  -> ((SomeAsync, Async (f t)) -> IO (f r))+  -> ((SomeAsync, Async t) -> IO r)   -- ^ The continuation; fst is sequential part, snd is value part.-  -> IO (f r)-runConcurrentialK joiner runner sc sequentialPart k = case sc of+  -> IO r+runConcurrentialK cc sequentialPart k = case cc of     SCAtom choice -> case choice of         -- The async created becomes the sequential part and the value         -- part. So when another Sequential is encountered, its value part         -- will have to wait for this computation to complete.         Sequential em -> withAsync-                         (waitSomeAsync sequentialPart >> runner em)+                         (waitSomeAsync sequentialPart >> em)                          (\async -> k (SomeAsync async, async))         -- The async created is the value part, but the sequential part         -- remains the same.         Concurrent em -> withAsync-                         (runner em)+                         (em)                          (\async -> k (sequentialPart, async))      SCBind sc next ->-        runConcurrentialK joiner runner sc sequentialPart $ \(sequentialPart, asyncS) -> do+        runConcurrentialK sc sequentialPart $ \(sequentialPart, asyncS) -> do         synchronizeSequentialPart <- newEmptyMVar         let waitAndContinue = do                 s <- wait asyncS@@ -165,13 +145,10 @@                         wait valuePart                 let continue = \x ->                         runConcurrentialK-                        joiner-                        runner                         (next x)                         sequentialPart                         synchronizeAndWait-                let unretracted = fmap continue s-                fmap join (joiner unretracted)+                continue s         -- This is a very sensitive part of the definition. We fire off a thread         -- to wait for @asyncS@ and then continue through @next@, but we also         -- create a thread which blocks until the aforementioned has determined@@ -185,44 +162,27 @@             k (SomeAsync sequentialPart, async)      SCAp left right ->-        runConcurrentialK joiner runner left sequentialPart $ \(sequentialPart, asyncF) ->-        runConcurrentialK joiner runner right sequentialPart $ \(sequentialPart, asyncX) ->+        runConcurrentialK left sequentialPart $ \(sequentialPart, asyncF) ->+        runConcurrentialK right sequentialPart $ \(sequentialPart, asyncX) ->         let waitAndApply = do                 f <- wait asyncF                 x <- wait asyncX-                return $ f <*> x+                return $ f x         in  withAsync waitAndApply (\async -> k (sequentialPart, async)) --- | Run a Concurrential term, realizing the effects of the IO-like terms which+-- | Run a Concurrential term, realizing the effects of the IO terms which --   compose it. runConcurrential-  :: (Functor f, Applicative f, Monad f)-  => Joiner f-  -> Runner m f-  -> Concurrential m t-  -> (Async (f t) -> IO (f r))+  :: Concurrential t+  -> (Async t -> IO r)   -- ^ Similar contract to withAsync; the Async argument is useless outside of   -- this function.-  -> IO (f r)-runConcurrential joiner runner c k = do+  -> IO r+runConcurrential cc k = do     let action = \sequentialPart ->-            runConcurrentialK joiner runner c (SomeAsync sequentialPart) (k . snd)+            runConcurrentialK cc (SomeAsync sequentialPart) (k . snd)     withAsync (return ()) action -runConcurrentialSimple :: Concurrential IO t -> (Async t -> IO r) -> IO r-runConcurrentialSimple c k = runIdentity <$> runConcurrential simpleJoiner simpleRunner c (continue k)--  where--    continue :: (Async t -> IO r) -> (Async (Identity t) -> IO (Identity r))-    continue k = \async -> Identity <$> k (fmap runIdentity async)--    simpleJoiner :: Joiner Identity-    simpleJoiner = fmap Identity . runIdentity--    simpleRunner :: Runner IO Identity-    simpleRunner = fmap Identity- -- | Create an effect which must be run sequentially. --   If a @sequentially io@ appears in a @Concurrential t@ term then it will --   always be run to completion before any later sequential part of the term@@ -241,9 +201,8 @@ --   important point: @concurrently otherIo@ may be run before, during or after --   @sequentially io@! The ordering through applicative combinators is --   guaranteed only among sequential terms.----sequentially :: m t -> Concurrential m t-sequentially = SCAtom . Sequential+sequentially :: IO t -> ConcurrentialAp t+sequentially = ConcurrentialAp . SCAtom . Sequential  -- | Create an effect which is run concurrently where possible, i.e. whenever it --   combined applicatively with other terms. For instance:@@ -256,5 +215,10 @@ --   When running the term @a@, the IO term @io@ will be run concurrently with --   @someConcurrential@, but not so in @b@, because monadic composition has --   been used.-concurrently :: m t -> Concurrential m t-concurrently = SCAtom . Concurrent+concurrently :: IO t -> ConcurrentialAp t+concurrently = ConcurrentialAp . SCAtom . Concurrent++-- | Inject a ConcurrentialAp into Concurrential, losing the+--   concurrency-enabling Applicative instance but gaining a Monad instance.+concurrentially :: ConcurrentialAp t -> Concurrential t+concurrentially = unConcurrentialAp