| Safe Haskell | Safe-Inferred | 
|---|
Control.Proxy.Class
Contents
Description
This module defines the theoretical framework underpinning this library
- class ProxyInternal p => Proxy p  where- request :: Monad m => a' -> p a' a b' b m a
- (>\\) :: Monad m => (b' -> p a' a x' x m b) -> p b' b x' x m c -> p a' a x' x m c
- respond :: Monad m => b -> p a' a b' b m b'
- (//>) :: Monad m => p x' x b' b m a' -> (b -> p x' x c' c m b') -> p x' x c' c m a'
- pull :: (Monad m, Proxy p) => a' -> p a' a a' a m r
- (->>) :: Monad m => (b' -> p a' a b' b m r) -> p b' b c' c m r -> p a' a c' c m r
- push :: (Monad m, Proxy p) => a -> p a' a a' a m r
- (>>~) :: Monad m => p a' a b' b m r -> (b -> p b' b c' c m r) -> p a' a c' c m r
- turn :: Monad m => p a' a b' b m r -> p b b' a a' m r
 
- (>->) :: (Monad m, Proxy p) => (b' -> p a' a b' b m r) -> (c'_ -> p b' b c' c m r) -> c'_ -> p a' a c' c m r
- (>~>) :: (Monad m, Proxy p) => (a_ -> p a' a b' b m r) -> (b -> p b' b c' c m r) -> a_ -> p a' a c' c m r
- (\>\) :: (Monad m, Proxy p) => (b' -> p a' a x' x m b) -> (c' -> p b' b x' x m c) -> c' -> p a' a x' x m c
- (/>/) :: (Monad m, Proxy p) => (a -> p x' x b' b m a') -> (b -> p x' x c' c m b') -> a -> p x' x c' c m a'
- (<-<) :: (Monad m, Proxy p) => (c' -> p b' b c' c m r) -> (b' -> p a' a b' b m r) -> c' -> p a' a c' c m r
- (<~<) :: (Monad m, Proxy p) => (b -> p b' b c' c m r) -> (a -> p a' a b' b m r) -> a -> p a' a c' c m r
- (/</) :: (Monad m, Proxy p) => (c' -> p b' b x' x m c) -> (b' -> p a' a x' x m b) -> c' -> p a' a x' x m c
- (\<\) :: (Monad m, Proxy p) => (b -> p x' x c' c m b') -> (a -> p x' x b' b m a') -> a -> p x' x c' c m a'
- (<<-) :: (Monad m, Proxy p) => p b' b c' c m r -> (b' -> p a' a b' b m r) -> p a' a c' c m r
- (~<<) :: (Monad m, Proxy p) => (b -> p b' b c' c m r) -> p a' a b' b m r -> p a' a c' c m r
- (//<) :: (Monad m, Proxy p) => p b' b x' x m c -> (b' -> p a' a x' x m b) -> p a' a x' x m c
- (<\\) :: (Monad m, Proxy p) => (b -> p x' x c' c m b') -> p x' x b' b m a' -> p x' x c' c m a'
- newtype  RespondT p a' a b' m b = RespondT {- runRespondT :: p a' a b' b m b'
 
- newtype  RequestT p a b' b m a' = RequestT {- runRequestT :: p a' a b' b m a
 
- data C
- type Pipe p a b = p () a () b
- type Producer p b = p C () () b
- type Consumer p a = p () a () C
- type CoPipe p a' b' = p a' () b' ()
- type CoProducer p a' = p a' () () C
- type CoConsumer p b' = p C () b' ()
- type Client p a' a = p a' a () C
- type Server p b' b = p C () b' b
- type Session p = p C () () C
- type ProduceT p = RespondT p C () ()
- type CoProduceT p = RequestT p () () C
- class  ProxyInternal p  where- return_P :: Monad m => r -> p a' a b' b m r
- (?>=) :: Monad m => p a' a b' b m r -> (r -> p a' a b' b m r') -> p a' a b' b m r'
- lift_P :: Monad m => m r -> p a' a b' b m r
- hoist_P :: Monad m => (forall r. m r -> n r) -> p a' a b' b m r' -> p a' a b' b n r'
- liftIO_P :: MonadIO m => IO r -> p a' a b' b m r
- thread_P :: Monad m => p a' a b' b m r -> s -> p (a', s) (a, s) (b', s) (b, s) m (r, s)
 
- class Proxy p => MonadPlusP p where
- idT :: (Monad m, Proxy p) => a' -> p a' a a' a m r
- coidT :: (Monad m, Proxy p) => a -> p a' a a' a m r
- class Proxy p => ListT p
- runRespondK :: (q -> RespondT p a' a b' m b) -> q -> p a' a b' b m b'
- runRequestK :: (q -> RequestT p a b' b m a') -> q -> p a' a b' b m a
The Proxy Class
class ProxyInternal p => Proxy p whereSource
The Proxy class defines a Monad that intersects four streaming
    categories:
-  The "request" category: requestand (\>\)
-  The "respond" category: respondand (/>/)
-  The "pull" category: pulland (>->)
-  The "push" category: pushand (>~>)
This class requires the "point-ful" version of each category's composition operator for efficiency.
Minimal definition:
Methods
request :: Monad m => a' -> p a' a b' b m aSource
request sends a value of type a' upstream and receives a value of
        type a.
(>\\) :: Monad m => (b' -> p a' a x' x m b) -> p b' b x' x m c -> p a' a x' x m cSource
(f >\\ p) replaces each request in p with f.
respond :: Monad m => b -> p a' a b' b m b'Source
respond sends a value of type b downstream and receives a value of
        type b'.
(//>) :: Monad m => p x' x b' b m a' -> (b -> p x' x c' c m b') -> p x' x c' c m a'Source
(p //> f) replaces each respond in p with f.
pull :: (Monad m, Proxy p) => a' -> p a' a a' a m rSource
pull = request >=> respond >=> pull
(->>) :: Monad m => (b' -> p a' a b' b m r) -> p b' b c' c m r -> p a' a c' c m rSource
push :: (Monad m, Proxy p) => a -> p a' a a' a m rSource
push = respond >=> request >=> push
(>>~) :: Monad m => p a' a b' b m r -> (b -> p b' b c' c m r) -> p a' a c' c m rSource
Composition operators
(>->) :: (Monad m, Proxy p) => (b' -> p a' a b' b m r) -> (c'_ -> p b' b c' c m r) -> c'_ -> p a' a c' c m rSource
(>~>) :: (Monad m, Proxy p) => (a_ -> p a' a b' b m r) -> (b -> p b' b c' c m r) -> a_ -> p a' a c' c m rSource
(\>\) :: (Monad m, Proxy p) => (b' -> p a' a x' x m b) -> (c' -> p b' b x' x m c) -> c' -> p a' a x' x m cSource
"request" composition
(f \>\ g) x = f >\\ g x
Compose two folds, generating a new fold
(/>/) :: (Monad m, Proxy p) => (a -> p x' x b' b m a') -> (b -> p x' x c' c m b') -> a -> p x' x c' c m a'Source
"respond" composition
(f />/ g) x = f x //> g
Compose two unfolds, generating a new unfold
Flipped operators
(<-<) :: (Monad m, Proxy p) => (c' -> p b' b c' c m r) -> (b' -> p a' a b' b m r) -> c' -> p a' a c' c m rSource
Equivalent to (>->) with the arguments flipped
(<~<) :: (Monad m, Proxy p) => (b -> p b' b c' c m r) -> (a -> p a' a b' b m r) -> a -> p a' a c' c m rSource
Equivalent to (>~>) with the arguments flipped
(/</) :: (Monad m, Proxy p) => (c' -> p b' b x' x m c) -> (b' -> p a' a x' x m b) -> c' -> p a' a x' x m cSource
Equivalent to (\>\) with the arguments flipped
(\<\) :: (Monad m, Proxy p) => (b -> p x' x c' c m b') -> (a -> p x' x b' b m a') -> a -> p x' x c' c m a'Source
Equivalent to (/>/) with the arguments flipped
(<<-) :: (Monad m, Proxy p) => p b' b c' c m r -> (b' -> p a' a b' b m r) -> p a' a c' c m rSource
Equivalent to (->>) with the arguments flipped
(~<<) :: (Monad m, Proxy p) => (b -> p b' b c' c m r) -> p a' a b' b m r -> p a' a c' c m rSource
Equivalent to (>>~) with the arguments flipped
(//<) :: (Monad m, Proxy p) => p b' b x' x m c -> (b' -> p a' a x' x m b) -> p a' a x' x m cSource
Equivalent to (>\\) with the arguments flipped
(<\\) :: (Monad m, Proxy p) => (b -> p x' x c' c m b') -> p x' x b' b m a' -> p x' x c' c m a'Source
Equivalent to (//>) with the arguments flipped
ListT Monad Transformers
The RespondT monad transformer is equivalent to ListT over the
    downstream output.  The RespondT Kleisli category corresponds to the
    "respond" category.
The RequestT monad transformer is equivalent to ListT over the upstream
    output.  The RequestT Kleisli category corresponds to the "request"
    category.
Unlike ListT from transformers, these monad transformers are correct by
    construction and always satisfy the monad and monad transformer laws.
newtype RespondT p a' a b' m b Source
A monad transformer over a proxy's downstream output
Constructors
| RespondT | |
| Fields 
 | |
Instances
| Proxy p => MonadTrans (RespondT p a' a b') | |
| (Monad m, Proxy p) => Monad (RespondT p a' a b' m) | |
| (Monad m, Proxy p) => Functor (RespondT p a' a b' m) | |
| (Monad m, Proxy p, Monoid b') => MonadPlus (RespondT p a' a b' m) | |
| (Monad m, Proxy p) => Applicative (RespondT p a' a b' m) | |
| (Monad m, Proxy p, Monoid b') => Alternative (RespondT p a' a b' m) | |
| (MonadIO m, Proxy p) => MonadIO (RespondT p a' a b' m) | 
newtype RequestT p a b' b m a' Source
A monad transformer over a proxy's upstream output
Constructors
| RequestT | |
| Fields 
 | |
Instances
| Proxy p => MonadTrans (RequestT p a' a b') | |
| (Monad m, Proxy p) => Monad (RequestT p a b' b m) | |
| (Monad m, Proxy p) => Functor (RequestT p a b' b m) | |
| (Monad m, Proxy p, Monoid a) => MonadPlus (RequestT p a b' b m) | |
| (Monad m, Proxy p) => Applicative (RequestT p a b' b m) | |
| (Monad m, Proxy p, Monoid a) => Alternative (RequestT p a b' b m) | |
| (MonadIO m, Proxy p) => MonadIO (RequestT p a b' b m) | 
Synonyms
type CoProducer p a' = p a' () () CSource
A CoPipe that produces values flowing upstream
CoProducers never respond.
type CoConsumer p b' = p C () b' ()Source
A CoConsumer that consumes values flowing upstream
CoConsumers never request.
type CoProduceT p = RequestT p () () CSource
CoProduceT is ListT over the upstream output
Laws
First, all proxies sit at the intersection of five categories:
- The Kleisli category (all proxies are monads)
return >=> f = f f >=> return = f (f >=> g) >=> h = f >=> (g >=> h)
- The "request" category
request \>\ f = f f \>\ request = f (f \>\ g) \>\ h = f \>\ (g \>\ h)
- The "respond" category
respond />/ f = f f />/ respond = f (f />/ g) />/ h = f />/ (g />/ h)
- The "pull" category
pull >-> f = f f >-> pull = f (f >-> g) >-> h = (f >-> g) >-> h
- The "push" category
push >~> f = f f >~> push = f (f >~> g) >~> h = f >~> (g >~> h)
Second, (turn .) transforms each streaming category into its dual:
- The "request" category
turn . request = respond turn . (f \>\ g) = turn . f \<\ turn . g
- The "respond" category
turn . respond = request turn . (f />/ g) = turn . f /</ turn. g
- The "pull" category
turn . pull = push turn . (f >-> g) = turn . f <~< turn . g
- The "push" category
turn . push = pull turn . (f >~> g) = turn . f <-< turn . g
Third, all proxies are monad transformers and must satisfy the monad transformer laws, using:
- lift = lift_P 
Fourth, all proxies are functors in the category of monads and must satisfy the functor laws, using:
- hoist = hoist_P 
Fifth, (\>\) and (/>/) both define functors between Kleisli categories
a \>\ (b >=> c) = (a \>\ b) >=> (a \>\ c) a \>\ return = return
(b >=> c) />/ a = (b />/ a) >=> (c />/ a) return />/ a = return
Sixth, all proxies must satisfy these additional Proxy laws:
 p \>\ lift . f = lift . f
 p \>\ respond  = respond
 lift . f />/ p = lift . f
 request />/  p = request
 pull = request >=> respond >=> pull
 push = respond >=> request >=> push
 p1 >-> lift . f = lift . f
 p1 >-> (lift . f >=> respond >=> p2) = lift . f >=> respond >=> (p1 >-> p2)
 (lift . g >=> respond >=> p1) >-> (lift . f >=> request >=> lift . h >=> p2)
     = lift . (f >=> g >=> h) >=> (p1 >-> p2)
 (lift . g >=> request >=> p1) >-> (lift . f >=> request >=> p2)
     = lift . (f >=> g) >=> request >=> (p1 >~> p2)
 lift . f >~> p2 = lift . f
 (lift . f >=> request >=> p1) >~> p2 = lift . f >=> request >=> (p1 >~> p2)
 (lift . f >=> respond >=> lift . h >=> p1) >~> (lift . g >=> request >=> p2)
     = lift . (f >=> g >=> h) >=> (p1 >~> p2)
 (lift . f >=> respond >=> p1) >~> (lift . g >=> respond >=> p2)
     = lift . (f >=> g) >=> (p1 >-> p2)
Polymorphic proxies
The ProxyInternal and MonadPlusP type classes duplicate methods from
    more familiar type classes.  These duplicate methods serve two purposes.
First, this library requires type class instances that would otherwise be impossible to define without providing higher-kinded constraints. Rather than use the following illegal polymorphic constraint:
instance (forall a' a b' b . MonadTrans (p a' a b' b)) => ...
... the instance can instead use the following Haskell98 constraint:
instance (Proxy p) => ...
Second, these type classes don't require the FlexibleContexts extension
    to use and substantially clean up constraints in type signatures.  They
    convert messy constraints like this:
p :: (MonadP (p a' a b' b m), MonadTrans (p a' a b' b)) => ...
.. into cleaner and more general constraints like this:
p :: (Proxy p) => ...
ProxyInternal and MonadPlusP exist solely for internal type class
    plumbing and I discourage you from using the methods in these classes
    unless you enjoy making your code less readable.  Instead, you can use all
    the original type classes as long as you embed your proxy code within at
    least one proxy transformer (or IdentityP if don't use any transformers).
    The type-class machinery will then automatically convert the messier and
    less polymorphic constraints to the simpler and more general constraints.
For example, consider the following almost-correct definition for mapMD
    (from Control.Proxy.Prelude.Base):
 import Control.Monad.Trans.Class
 import Control.Proxy
 mapMD f = foreverK $ \a' -> do
     a <- request a'
     b <- lift (f a)
     respond b
The compiler infers the following messy constraint:
mapMD :: (Monad m, Monad (p x a x b m), MonadTrans (p x a x b), Proxy p) => (a -> m b) -> x -> p x a x b m r
Instead, you can embed the code in the IdentityP proxy transformer by
    wrapping it in runIdentityK:
 --        |difference|  
 mapMD f = runIdentityK $ foreverK $ \a' -> do
     a <- request a'
     b <- lift (f a)
     respond b
... and now the compiler collapses all the constraints into the Proxy
    constraint:
mapMD :: (Monad m, Proxy p) => (a -> m b) -> x -> p x a x b m r
You do not incur any performance penalty for writing polymorphic code or
    embedding it in IdentityP.  This library employs several rewrite RULES
    which transform your polymorphic code into the equivalent type-specialized
    hand-tuned code.  These rewrite rules fire very robustly and they do not
    require any assistance on your part from compiler pragmas like INLINE,
    NOINLINE or SPECIALIZE.
If you nest proxies within proxies:
 example () = do
     request ()
     lift $ request ()
     lift $ lift $ request ()
... then you can still keep the nice constraints using:
 example () = runIdentityP . hoist (runIdentityP . hoist runIdentityP) $ do
     request ()
     lift $ request ()
     lift $ lift $ request ()
You don't need to use runIdentityP / runIdentityK if you use any other
    proxy transformers (In fact you can't, it's a type error).  The following
    code example illustrates this, where the throw command (from the EitherP
    proxy transformer) suffices to guide the compiler to the cleaner type
    signature:
 import Control.Monad
 import Control.Proxy
 import qualified Control.Proxy.Trans.Either as E
 example :: (Monad m, Proxy p) => () -> Producer (EitherP String p) Char m ()
 example () = do
     c <- request ()
     when (c == ' ') $ E.throw "Error: received space"
     respond c
class ProxyInternal p whereSource
The (ProxyInternal p) constraint is (basically) equivalent to the
    following polymorphic constraint:
 (forall a' a b' b m . (Monad m)
     => Monad      (p a' a b' b m)
     ,  MonadTrans (p a' a b' b  )
     ,  MFunctor   (p a' a b' b m)
     ,  MonadIO    (p a' a b' b m)
     ) => ...
Methods
return_P :: Monad m => r -> p a' a b' b m rSource
(?>=) :: Monad m => p a' a b' b m r -> (r -> p a' a b' b m r') -> p a' a b' b m r'Source
lift_P :: Monad m => m r -> p a' a b' b m rSource
hoist_P :: Monad m => (forall r. m r -> n r) -> p a' a b' b m r' -> p a' a b' b n r'Source
liftIO_P :: MonadIO m => IO r -> p a' a b' b m rSource
thread_P :: Monad m => p a' a b' b m r -> s -> p (a', s) (a, s) (b', s) (b, s) m (r, s)Source
Instances
| ProxyInternal ProxyFast | |
| ProxyInternal ProxyCorrect | |
| Proxy p => ProxyInternal (IdentityP p) | |
| Proxy p => ProxyInternal (CodensityP p) | |
| Proxy p => ProxyInternal (MaybeP p) | |
| Proxy p => ProxyInternal (EitherP e p) | |
| Proxy p => ProxyInternal (ReaderP i p) | |
| Proxy p => ProxyInternal (StateP s p) | |
| Proxy p => ProxyInternal (WriterP w p) | 
class Proxy p => MonadPlusP p whereSource
The (MonadPlusP p) constraint is equivalent to the following polymorphic
    constraint:
(forall a' a b' b m . (Monad m) => MonadPlus (p a' a b' b m)) => ...
Methods
mzero_P :: Monad m => p a' a b' b m rSource
mplus_P :: Monad m => p a' a b' b m r -> p a' a b' b m r -> p a' a b' b m rSource
Instances
| MonadPlusP p => MonadPlusP (IdentityP p) | |
| MonadPlusP p => MonadPlusP (CodensityP p) | |
| Proxy p => MonadPlusP (MaybeP p) | |
| (Proxy p, Monoid e) => MonadPlusP (EitherP e p) | |
| MonadPlusP p => MonadPlusP (ReaderP i p) | |
| MonadPlusP p => MonadPlusP (StateP s p) | |
| MonadPlusP p => MonadPlusP (WriterP w p) | 
Deprecated
These will be removed in version 4.0.0
runRespondK :: (q -> RespondT p a' a b' m b) -> q -> p a' a b' b m b'Source
Deprecated: Use '(runRespondT .)' instead
runRequestK :: (q -> RequestT p a b' b m a') -> q -> p a' a b' b m aSource
Deprecated: Use '(runRequestK .)' instead