Pipes.Core

pipes-4.3.1: Compositional pipelines

Safe Haskell | Trustworthy
Language | Haskell2010

Pipes.Core

Contents

- Proxy Monad Transformer
- Categories
  - Respond
  - Request
  - Push
  - Pull
  - Reflect
- Concrete Type Synonyms
- Polymorphic Type Synonyms
- Flipped operators
- Re-exports

Description

The core functionality for the `Proxy` monad transformer

Read Pipes.Tutorial if you want a beginners tutorial explaining how to use this library. The documentation in this module targets more advanced users who want to understand the theory behind this library.

This module is not exported by default, and I recommend you use the unidirectional operations exported by the Pipes module if you can. You should only use this module if you require advanced features like:

- bidirectional communication, or:
- push-based `Pipe`s.

Synopsis

- data Proxy a' a b' b m r
- runEffect :: Monad m => Effect m r -> m r
- respond :: Monad m => a -> Proxy x' x a' a m a'
- (/>/) :: Monad m => (a -> Proxy x' x b' b m a') -> (b -> Proxy x' x c' c m b') -> a -> Proxy x' x c' c m a'
- (//>) :: Monad m => Proxy x' x b' b m a' -> (b -> Proxy x' x c' c m b') -> Proxy x' x c' c m a'
- request :: Monad m => a' -> Proxy a' a y' y m a
- (\>\) :: Monad m => (b' -> Proxy a' a y' y m b) -> (c' -> Proxy b' b y' y m c) -> c' -> Proxy a' a y' y m c
- (>\\) :: Monad m => (b' -> Proxy a' a y' y m b) -> Proxy b' b y' y m c -> Proxy a' a y' y m c
- push :: Monad m => a -> Proxy a' a a' a m r
- (>~>) :: Monad m => (_a -> Proxy a' a b' b m r) -> (b -> Proxy b' b c' c m r) -> _a -> Proxy a' a c' c m r
- (>>~) :: Monad m => Proxy a' a b' b m r -> (b -> Proxy b' b c' c m r) -> Proxy a' a c' c m r
- pull :: Monad m => a' -> Proxy a' a a' a m r
- (>+>) :: Monad m => (b' -> Proxy a' a b' b m r) -> (_c' -> Proxy b' b c' c m r) -> _c' -> Proxy a' a c' c m r
- (+>>) :: Monad m => (b' -> Proxy a' a b' b m r) -> Proxy b' b c' c m r -> Proxy a' a c' c m r
- reflect :: Monad m => Proxy a' a b' b m r -> Proxy b b' a a' m r
- data X
- type Effect = Proxy X () () X
- type Producer b = Proxy X () () b
- type Pipe a b = Proxy () a () b
- type Consumer a = Proxy () a () X
- type Client a' a = Proxy a' a () X
- type Server b' b = Proxy X () b' b
- type Effect' m r = forall x' x y' y. Proxy x' x y' y m r
- type Producer' b m r = forall x' x. Proxy x' x () b m r
- type Consumer' a m r = forall y' y. Proxy () a y' y m r
- type Client' a' a m r = forall y' y. Proxy a' a y' y m r
- type Server' b' b m r = forall x' x. Proxy x' x b' b m r
- (\<\) :: Monad m => (b -> Proxy x' x c' c m b') -> (a -> Proxy x' x b' b m a') -> a -> Proxy x' x c' c m a'
- (/</) :: Monad m => (c' -> Proxy b' b x' x m c) -> (b' -> Proxy a' a x' x m b) -> c' -> Proxy a' a x' x m c
- (<~<) :: Monad m => (b -> Proxy b' b c' c m r) -> (a -> Proxy a' a b' b m r) -> a -> Proxy a' a c' c m r
- (~<<) :: Monad m => (b -> Proxy b' b c' c m r) -> Proxy a' a b' b m r -> Proxy a' a c' c m r
- (<+<) :: Monad m => (c' -> Proxy b' b c' c m r) -> (b' -> Proxy a' a b' b m r) -> c' -> Proxy a' a c' c m r
- (<\\) :: Monad m => (b -> Proxy x' x c' c m b') -> Proxy x' x b' b m a' -> Proxy x' x c' c m a'
- (//<) :: Monad m => Proxy b' b y' y m c -> (b' -> Proxy a' a y' y m b) -> Proxy a' a y' y m c
- (<<+) :: Monad m => Proxy b' b c' c m r -> (b' -> Proxy a' a b' b m r) -> Proxy a' a c' c m r
- closed :: X -> a

# Proxy Monad Transformer

Diagrammatically, you can think of a `Proxy` as having the following shape:

     Upstream | Downstream
         +---------+
         |         |
     a' <==       <== b'
         |         |
     a  ==>       ==> b
         |    |    |
         +----|----+
              v
              r

You can connect proxies together in five different ways:

- (`>+>`): connect pull-based streams
- (`>~>`): connect push-based streams
- (`\>\`): chain folds
- (`/>/`): chain unfolds
- (`>=>`): sequence proxies

data Proxy a' a b' b m r #

A `Proxy` is a monad transformer that receives and sends information on both an upstream and downstream interface.

The type variables signify:

- `a'` and `a` - The upstream interface, where `(a')`s go out and `(a)`s come in
- `b'` and `b` - The downstream interface, where `(b)`s go out and `(b')`s come in
- `m` - The base monad
- `r` - The return value

Instances

MonadError e m => MonadError e (Proxy a' a b' b m) # |
Methods throwError :: e -> Proxy a' a b' b m a # catchError :: Proxy a' a b' b m a -> (e -> Proxy a' a b' b m a) -> Proxy a' a b' b m a #
MonadReader r m => MonadReader r (Proxy a' a b' b m) # |
Methods ask :: Proxy a' a b' b m r # local :: (r -> r) -> Proxy a' a b' b m a -> Proxy a' a b' b m a # reader :: (r -> a) -> Proxy a' a b' b m a #
MonadState s m => MonadState s (Proxy a' a b' b m) # |
Methods get :: Proxy a' a b' b m s # put :: s -> Proxy a' a b' b m () # state :: (s -> (a, s)) -> Proxy a' a b' b m a #
MonadWriter w m => MonadWriter w (Proxy a' a b' b m) # |
Methods writer :: (a, w) -> Proxy a' a b' b m a # tell :: w -> Proxy a' a b' b m () # listen :: Proxy a' a b' b m a -> Proxy a' a b' b m (a, w) # pass :: Proxy a' a b' b m (a, w -> w) -> Proxy a' a b' b m a #
MFunctor (Proxy a' a b' b) # |
Methods hoist :: Monad m => (forall c. m c -> n c) -> Proxy a' a b' b m b -> Proxy a' a b' b n b #
MMonad (Proxy a' a b' b) # |
Methods embed :: Monad n => (forall c. m c -> Proxy a' a b' b n c) -> Proxy a' a b' b m b -> Proxy a' a b' b n b #
MonadTrans (Proxy a' a b' b) # |
Methods lift :: Monad m => m a -> Proxy a' a b' b m a #
Monad m => Monad (Proxy a' a b' b m) # |
Methods (>>=) :: Proxy a' a b' b m a -> (a -> Proxy a' a b' b m b) -> Proxy a' a b' b m b # (>>) :: Proxy a' a b' b m a -> Proxy a' a b' b m b -> Proxy a' a b' b m b # return :: a -> Proxy a' a b' b m a # fail :: String -> Proxy a' a b' b m a #
Monad m => Functor (Proxy a' a b' b m) # |
Methods fmap :: (a -> b) -> Proxy a' a b' b m a -> Proxy a' a b' b m b # (<$) :: a -> Proxy a' a b' b m b -> Proxy a' a b' b m a #
Monad m => Applicative (Proxy a' a b' b m) # |
Methods pure :: a -> Proxy a' a b' b m a # (<*>) :: Proxy a' a b' b m (a -> b) -> Proxy a' a b' b m a -> Proxy a' a b' b m b # (*>) :: Proxy a' a b' b m a -> Proxy a' a b' b m b -> Proxy a' a b' b m b # (<*) :: Proxy a' a b' b m a -> Proxy a' a b' b m b -> Proxy a' a b' b m a #
MonadIO m => MonadIO (Proxy a' a b' b m) # |
Methods liftIO :: IO a -> Proxy a' a b' b m a #
MonadThrow m => MonadThrow (Proxy a' a b' b m) # |
Methods throwM :: Exception e => e -> Proxy a' a b' b m a #
MonadCatch m => MonadCatch (Proxy a' a b' b m) # |
Methods catch :: Exception e => Proxy a' a b' b m a -> (e -> Proxy a' a b' b m a) -> Proxy a' a b' b m a #
(Monad m, Monoid r) => Monoid (Proxy a' a b' b m r) # |
Methods mempty :: Proxy a' a b' b m r # mappend :: Proxy a' a b' b m r -> Proxy a' a b' b m r -> Proxy a' a b' b m r # mconcat :: [Proxy a' a b' b m r] -> Proxy a' a b' b m r #

runEffect :: Monad m => Effect m r -> m r #

Run a self-contained `Effect`, converting it back to the base monad

# Categories

A `Category` is a set of components that you can connect with a composition operator, (`.`), that has an identity, `id`. The (`.`) and `id` must satisfy the following three `Category` laws:

    -- Left identity
    id . f = f

    -- Right identity
    f . id = f

    -- Associativity
    (f . g) . h = f . (g . h)

The `Proxy` type sits at the intersection of five separate categories, four of which are named after their identity:

                         Identity   | Composition |  Point-ful
                      +-------------+-------------+-------------+
     respond category |   respond   |     />/     |     //>     |
     request category |   request   |     \>\     |     >\\     |
        push category |   push      |     >~>     |     >>~     |
        pull category |   pull      |     >+>     |     +>>     |
     Kleisli category |   return    |     >=>     |     >>=     |
                      +-------------+-------------+-------------+

Each composition operator has a "point-ful" version, analogous to how (`>>=`) is the point-ful version of (`>=>`). For example, (`//>`) is the point-ful version of (`/>/`). The convention is that the odd character out faces the argument that is a function.

## Respond

The `respond` category closely corresponds to the generator design pattern.

The `respond` category obeys the category laws, where `respond` is the identity and (`/>/`) is composition:

    -- Left identity
    respond />/ f = f

    -- Right identity
    f />/ respond = f

    -- Associativity
    (f />/ g) />/ h = f />/ (g />/ h)

The following diagrams show the flow of information:

    respond :: Monad m
           =>  a -> Proxy x' x a' a m a'

              a
              |
         +----|----+
         |    |    |
     x' <==   \ /==== a'
         |     X   |
     x  ==>   / \===> a
         |    |    |
         +----|----+
              v
              a'

    (/>/) :: Monad m
          => (a -> Proxy x' x b' b m a')
          -> (b -> Proxy x' x c' c m b')
          -> (a -> Proxy x' x c' c m a')

              a                   /===> b                      a
              |                  /      |                      |
         +----|----+            /  +----|----+            +----|----+
         |    v    |           /   |    v    |            |    v    |
     x' <==       <== b' <==\ / x'<==       <== c'    x' <==       <== c'
         |    f    |         X     |    g    |     =      | f />/ g |
     x  ==>       ==> b  ===/ \ x ==>       ==> c     x  ==>       ==> c'
         |    |    |           \   |    |    |            |    |    |
         +----|----+            \  +----|----+            +----|----+
              v                  \      v                      v
              a'                  \==== b'                     a'

    (//>) :: Monad m
          => Proxy x' x b' b m a'
          -> (b -> Proxy x' x c' c m b')
          -> Proxy x' x c' c m a'

                                  /===> b
                                 /      |
         +---------+            /  +----|----+            +---------+
         |         |           /   |    v    |            |         |
     x' <==       <== b' <==\ / x'<==       <== c'    x' <==       <== c'
         |    f    |         X     |    g    |     =      | f //> g |
     x  ==>       ==> b  ===/ \ x ==>       ==> c     x  ==>       ==> c'
         |    |    |           \   |    |    |            |    |    |
         +----|----+            \  +----|----+            +----|----+
              v                  \      v                      v
              a'                  \==== b'                     a'

respond :: Monad m => a -> Proxy x' x a' a m a' #

Send a value of type `a` downstream and block waiting for a reply of type `a'`

`respond` is the identity of the respond category.

(/>/) infixr 4 #

Arguments

:: Monad m |
=> (a -> Proxy x' x b' b m a') |
-> (b -> Proxy x' x c' c m b') |
-> a -> Proxy x' x c' c m a' |

Compose two unfolds, creating a new unfold

    (f />/ g) x = f x //> g

(`/>/`) is the composition operator of the respond category.

(//>) infixl 3 #

Arguments

:: Monad m |
=> Proxy x' x b' b m a' |
-> (b -> Proxy x' x c' c m b') |
-> Proxy x' x c' c m a' |

`(p //> f)` replaces each `respond` in `p` with `f`.

Point-ful version of (`/>/`)

## Request

The `request` category closely corresponds to the iteratee design pattern.

The `request` category obeys the category laws, where `request` is the identity and (`\>\`) is composition:

    -- Left identity
    request \>\ f = f

    -- Right identity
    f \>\ request = f

    -- Associativity
    (f \>\ g) \>\ h = f \>\ (g \>\ h)

The following diagrams show the flow of information:

    request :: Monad m
            =>  a' -> Proxy a' a y' y m a

              a'
              |
         +----|----+
         |    |    |
     a' <=====/   <== y'
         |         |
     a  ======\   ==> y
         |    |    |
         +----|----+
              v
              a

    (\>\) :: Monad m
          => (b' -> Proxy a' a y' y m b)
          -> (c' -> Proxy b' b y' y m c)
          -> (c' -> Proxy a' a y' y m c)

              b'<=====\                c'                     c'
              |        \               |                      |
         +----|----+    \         +----|----+            +----|----+
         |    v    |     \        |    v    |            |    v    |
     a' <==       <== y'  \== b' <==       <== y'    a' <==       <== y'
         |    f    |              |    g    |     =      | f \>\ g |
     a  ==>       ==> y   /=> b  ==>       ==> y     a  ==>       ==> y
         |    |    |     /        |    |    |            |    |    |
         +----|----+    /         +----|----+            +----|----+
              v        /               v                      v
              b ======/                c                      c

    (>\\) :: Monad m
          => (b' -> Proxy a' a y' y m b)
          -> Proxy b' b y' y m c
          -> Proxy a' a y' y m c

              b'<=====\
              |        \
         +----|----+    \         +---------+            +---------+
         |    v    |     \        |         |            |         |
     a' <==       <== y'  \== b' <==       <== y'    a' <==       <== y'
         |    f    |              |    g    |     =      | f >\\ g |
     a  ==>       ==> y   /=> b  ==>       ==> y     a  ==>       ==> y
         |    |    |     /        |    |    |            |    |    |
         +----|----+    /         +----|----+            +----|----+
              v        /               v                      v
              b ======/                c                      c

request :: Monad m => a' -> Proxy a' a y' y m a #

Send a value of type `a'` upstream and block waiting for a reply of type `a`

`request` is the identity of the request category.

(\>\) infixl 5 #

Arguments

:: Monad m |
=> (b' -> Proxy a' a y' y m b) |
-> (c' -> Proxy b' b y' y m c) |
-> c' -> Proxy a' a y' y m c |

Compose two folds, creating a new fold

    (f \>\ g) x = f >\\ g x

(`\>\`) is the composition operator of the request category.

(>\\) infixr 4 #

Arguments

:: Monad m |
=> (b' -> Proxy a' a y' y m b) |
-> Proxy b' b y' y m c |
-> Proxy a' a y' y m c |

`(f >\\ p)` replaces each `request` in `p` with `f`.

Point-ful version of (`\>\`)

## Push

The `push` category closely corresponds to push-based Unix pipes.

The `push` category obeys the category laws, where `push` is the identity and (`>~>`) is composition:

    -- Left identity
    push >~> f = f

    -- Right identity
    f >~> push = f

    -- Associativity
    (f >~> g) >~> h = f >~> (g >~> h)

The following diagram shows the flow of information:

    push  :: Monad m
          =>  a -> Proxy a' a a' a m r

              a
              |
         +----|----+
         |    v    |
     a' <============ a'
         |         |
     a  ============> a
         |    |    |
         +----|----+
              v
              r

    (>~>) :: Monad m
          => (a -> Proxy a' a b' b m r)
          -> (b -> Proxy b' b c' c m r)
          -> (a -> Proxy a' a c' c m r)

              a                b                      a
              |                |                      |
         +----|----+      +----|----+            +----|----+
         |    v    |      |    v    |            |    v    |
     a' <==       <== b' <==       <== c'    a' <==       <== c'
         |    f    |      |    g    |     =      | f >~> g |
     a  ==>       ==> b  ==>       ==> c     a  ==>       ==> c
         |    |    |      |    |    |            |    |    |
         +----|----+      +----|----+            +----|----+
              v                v                      v
              r                r                      r

push :: Monad m => a -> Proxy a' a a' a m r #

Forward responses followed by requests

    push = respond >=> request >=> push

`push` is the identity of the push category.

(>~>) infixr 8 #

Arguments

:: Monad m |
=> (_a -> Proxy a' a b' b m r) |
-> (b -> Proxy b' b c' c m r) |
-> _a -> Proxy a' a c' c m r |

Compose two proxies blocked while `request`ing data, creating a new proxy blocked while `request`ing data

    (f >~> g) x = f x >>~ g

(`>~>`) is the composition operator of the push category.

(>>~) infixl 7 #

Arguments

:: Monad m |
=> Proxy a' a b' b m r |
-> (b -> Proxy b' b c' c m r) |
-> Proxy a' a c' c m r |

`(p >>~ f)` pairs each `respond` in `p` with a `request` in `f`.

Point-ful version of (`>~>`)

## Pull

The `pull` category closely corresponds to pull-based Unix pipes.

The `pull` category obeys the category laws, where `pull` is the identity and (`>+>`) is composition:

    -- Left identity
    pull >+> f = f

    -- Right identity
    f >+> pull = f

    -- Associativity
    (f >+> g) >+> h = f >+> (g >+> h)

The following diagrams show the flow of information:

    pull  :: Monad m
          =>  a' -> Proxy a' a a' a m r

              a'
              |
         +----|----+
         |    v    |
     a' <============ a'
         |         |
     a  ============> a
         |    |    |
         +----|----+
              v
              r

    (>+>) :: Monad m
          -> (b' -> Proxy a' a b' b m r)
          -> (c' -> Proxy b' b c' c m r)
          -> (c' -> Proxy a' a c' c m r)

              b'               c'                     c'
              |                |                      |
         +----|----+      +----|----+            +----|----+
         |    v    |      |    v    |            |    v    |
     a' <==       <== b' <==       <== c'    a' <==       <== c'
         |    f    |      |    g    |     =      | f >+> g |
     a  ==>       ==> b  ==>       ==> c     a  ==>       ==> c
         |    |    |      |    |    |            |    |    |
         +----|----+      +----|----+            +----|----+
              v                v                      v
              r                r                      r

pull :: Monad m => a' -> Proxy a' a a' a m r #

Forward requests followed by responses:

    pull = request >=> respond >=> pull

`pull` is the identity of the pull category.

(>+>) infixl 7 #

Arguments

:: Monad m |
=> (b' -> Proxy a' a b' b m r) |
-> (_c' -> Proxy b' b c' c m r) |
-> _c' -> Proxy a' a c' c m r |

Compose two proxies blocked in the middle of `respond`ing, creating a new proxy blocked in the middle of `respond`ing

    (f >+> g) x = f +>> g x

(`>+>`) is the composition operator of the pull category.

(+>>) infixr 6 #

Arguments

:: Monad m |
=> (b' -> Proxy a' a b' b m r) |
-> Proxy b' b c' c m r |
-> Proxy a' a c' c m r |

`(f +>> p)` pairs each `request` in `p` with a `respond` in `f`.

Point-ful version of (`>+>`)

## Reflect

`(reflect .)` transforms each streaming category into its dual:

- The request category is the dual of the respond category

    reflect . respond = request

    reflect . (f />/ g) = reflect . f /</ reflect . g

    reflect . request = respond

    reflect . (f \>\ g) = reflect . f \<\ reflect . g

- The pull category is the dual of the push category

    reflect . push = pull

    reflect . (f >~> g) = reflect . f <+< reflect . g

    reflect . pull = push

    reflect . (f >+> g) = reflect . f <~< reflect . g

reflect :: Monad m => Proxy a' a b' b m r -> Proxy b b' a a' m r #

Switch the upstream and downstream ends

# Concrete Type Synonyms

data X #

The empty type, used to close output ends

When `Data.Void` is merged into `base`, this will change to:

    type X = Void

type Effect = Proxy X () () X #

An effect in the base monad

`Effect`s neither `await` nor `yield`

type Producer b = Proxy X () () b #

`Producer`s can only `yield`

type Pipe a b = Proxy () a () b #

`Pipe`s can both `await` and `yield`

type Consumer a = Proxy () a () X #

`Consumer`s can only `await`

type Client a' a = Proxy a' a () X #

`Client a' a` sends requests of type `a'` and receives responses of type `a`.

`Client`s only `request` and never `respond`.

type Server b' b = Proxy X () b' b #

`Server b' b` receives requests of type `b'` and sends responses of type `b`.

`Server`s only `respond` and never `request`.

# Polymorphic Type Synonyms

type Effect' m r = forall x' x y' y. Proxy x' x y' y m r #

Like `Effect`, but with a polymorphic type

type Producer' b m r = forall x' x. Proxy x' x () b m r #

Like `Producer`, but with a polymorphic type

type Consumer' a m r = forall y' y. Proxy () a y' y m r #

Like `Consumer`, but with a polymorphic type

type Client' a' a m r = forall y' y. Proxy a' a y' y m r #

Like `Client`, but with a polymorphic type

type Server' b' b m r = forall x' x. Proxy x' x b' b m r #

Like `Server`, but with a polymorphic type

# Flipped operators

(\<\) infixl 4 #

Arguments

:: Monad m |
=> (b -> Proxy x' x c' c m b') |
-> (a -> Proxy x' x b' b m a') |
-> a -> Proxy x' x c' c m a' |

Equivalent to (`/>/`) with the arguments flipped

(/</) infixr 5 #

Arguments

:: Monad m |
=> (c' -> Proxy b' b x' x m c) |
-> (b' -> Proxy a' a x' x m b) |
-> c' -> Proxy a' a x' x m c |

Equivalent to (`\>\`) with the arguments flipped

(<~<) infixl 8 #

Arguments

:: Monad m |
=> (b -> Proxy b' b c' c m r) |
-> (a -> Proxy a' a b' b m r) |
-> a -> Proxy a' a c' c m r |

Equivalent to (`>~>`) with the arguments flipped

(~<<) infixr 7 #

Arguments

:: Monad m |
=> (b -> Proxy b' b c' c m r) |
-> Proxy a' a b' b m r |
-> Proxy a' a c' c m r |

Equivalent to (`>>~`) with the arguments flipped

(<+<) infixr 7 #

Arguments

:: Monad m |
=> (c' -> Proxy b' b c' c m r) |
-> (b' -> Proxy a' a b' b m r) |
-> c' -> Proxy a' a c' c m r |

Equivalent to (`>+>`) with the arguments flipped

(<\\) infixr 3 #

Arguments

:: Monad m |
=> (b -> Proxy x' x c' c m b') |
-> Proxy x' x b' b m a' |
-> Proxy x' x c' c m a' |

Equivalent to (`//>`) with the arguments flipped

(//<) infixl 4 #

Arguments

:: Monad m |
=> Proxy b' b y' y m c |
-> (b' -> Proxy a' a y' y m b) |
-> Proxy a' a y' y m c |

Equivalent to (`>\\`) with the arguments flipped

(<<+) infixl 6 #

Arguments

:: Monad m |
=> Proxy b' b c' c m r |
-> (b' -> Proxy a' a b' b m r) |
-> Proxy a' a c' c m r |

Equivalent to (`+>>`) with the arguments flipped

# Re-exports

closed :: X -> a #

Use `closed` to "handle" impossible outputs