Copyright | (c) Alexander Vieth, 2015 |
---|---|
License | BSD3 |
Maintainer | aovieth@gmail.com |
Stability | experimental |
Portability | non-portable (GHC only) |
Safe Haskell | None |
Language | Haskell2010 |
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.
- data Concurrential m t
- type Runner f g = forall a. f a -> IO (g a)
- type Joiner g = forall a. g (IO a) -> IO (g a)
- runConcurrential :: (Functor f, Applicative f, Monad f) => Joiner f -> Runner m f -> Concurrential m t -> (Async (f t) -> IO (f r)) -> IO (f r)
- runConcurrentialSimple :: Concurrential IO t -> (Async t -> IO r) -> IO r
- sequentially :: m t -> Concurrential m t
- concurrently :: m t -> Concurrential m t
- wait :: Async a -> IO a
Documentation
data Concurrential m t Source
Description of computation which is composed of sequential and concurrent
parts in some monad m
.
Applicative m => Monad (Concurrential m) | |
Functor m => Functor (Concurrential m) | |
Applicative m => Applicative (Concurrential m) | |
Typeable ((* -> *) -> * -> *) Concurrential |
type Runner f g = forall a. f a -> IO (g a) Source
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 Joiner g = forall a. g (IO a) -> IO (g a) Source
A witness of this type proves that g is in some sense compatible with IO: we can bind through it.
:: (Functor f, Applicative f, Monad f) | |
=> Joiner f | |
-> Runner m f | |
-> Concurrential m t | |
-> (Async (f t) -> IO (f r)) | Similar contract to withAsync; the Async argument is useless outside of this function. |
-> IO (f r) |
Run a Concurrential term, realizing the effects of the IO-like terms which compose it.
runConcurrentialSimple :: Concurrential IO t -> (Async t -> IO r) -> IO r Source
sequentially :: m t -> Concurrential m t Source
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
is run. Consider the following terms:
a = someConcurrential *> sequentially io *> someOtherConcurrential b = someConcurrential *> concurrently io *> someOtherConcurrential c = someConcurrential *> sequentially io *> concurrently otherIo
When running the term a
, we are guaranteed that io
is completed before
any sequential part of someOtherConcurrential
is begun, but when running
the term b
, this is not the case; io
may be interleaved with or even
run after any part of someOtherConcurrential
. The term c
highlights an
important point: concurrently otherIo
may be run before, during or after
sequentially io
! The ordering through applicative combinators is
guaranteed only among sequential terms.
concurrently :: m t -> Concurrential m t Source
Create an effect which is run concurrently where possible, i.e. whenever it combined applicatively with other terms. For instance:
a = concurrently io *> someConcurrential b = concurrently io >> someConcurrential
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.