pipes-2.5.0: Compositional pipelines

Safe HaskellSafe-Inferred

Control.Proxy.Core

Contents

Description

A Proxy requests input from upstream and responds with output to downstream.

For an extended tutorial, consult Control.Proxy.Tutorial.

Synopsis

Types

data Proxy a' a b' b m r Source

A Proxy communicates with an upstream interface and a downstream interface.

The type variables of Proxy req_a resp_a req_b resp_b m r signify:

  • req_a - The request supplied to the upstream interface
  • resp_a - The response provided by the upstream interface
  • req_b - The request supplied by the downstream interface
  • resp_b - The response provided to the downstream interface
  • m - The base monad
  • r - The final return value

Constructors

Request a' (a -> Proxy a' a b' b m r) 
Respond b (b' -> Proxy a' a b' b m r) 
M (m (Proxy a' a b' b m r)) 
Pure r 

Instances

Interact Proxy 
Channel Proxy 
MonadTrans (Proxy a' a b' b) 
MFunctor (Proxy a' a b' b) 
Monad m => Monad (Proxy a' a b' b m) 
Monad m => Functor (Proxy a' a b' b m) 
(Functor (Proxy a' a b' b m), Monad m) => Applicative (Proxy a' a b' b m) 
(Monad (Proxy a' a b' b m), MonadIO m) => MonadIO (Proxy a' a b' b m) 

data C Source

The empty type, denoting a 'C'losed end

type Server req resp = Proxy C () req respSource

Server req resp receives requests of type req and sends responses of type resp.

Servers only respond and never request anything.

type Client req resp = Proxy req resp () CSource

Client req resp sends requests of type req and receives responses of type resp.

Clients only request and never respond to anything.

type Session = Proxy C () () CSource

A self-contained Session, ready to be run by runSession

Sessions never request anything or respond to anything.

Run Sessions

I provide two ways to run proxies:

  • runProxy, which discards unhandled output from either end
  • runSession, which type restricts its argument to ensure no loose ends

Both functions require that the input to each end is trivially satisfiable, (i.e. ()).

I recommend runProxy for most use cases since it is more convenient.

runSession only accepts sessions that do not send unhandled data flying off each end, which provides the following benefits:

  • It prevents against accidental data loss.
  • It protects against silent failures
  • It prevents wastefully draining a scarce resource by gratuitously driving it to completion

However, this restriction means that you must either duplicate every utility function to specialize them to the end-point positions (which I do not do), or explicitly close loose ends using the discard and ignore proxies:

 runSession $ discard <-< p <-< ignore

Use the 'K' versions of each command if you are running sessions nested within sessions. They provide a Kleisli arrow as their result suitable to be passed to another runProxy / runSession command.

runProxy :: Monad m => (() -> Proxy a' () () b m r) -> m rSource

Run a self-sufficient Proxy Kleisli arrow, converting it back to the base monad

runProxyK :: Monad m => (() -> Proxy a () () b m r) -> () -> m rSource

Run a self-sufficient Proxy Kleisli arrow, converting it back to a Kleisli arrow in the base monad

runSession :: Monad m => (() -> Session m r) -> m rSource

Run a self-contained Session Kleisli arrow, converting it back to the base monad

runSessionK :: Monad m => (() -> Session m r) -> () -> m rSource

Run a self-contained Session Kleisli arrow, converting it back to a Kleisli arrow in the base monad

Utility Proxies

discard provides a fallback client that gratuitously requests input from a server, but discards all responses.

ignore provides a fallback server that trivially responds with output to a client, but ignores all request parameters.

discard :: Monad m => () -> Proxy () a () C m rSource

Discard all responses

ignore :: Monad m => a -> Proxy C () a () m rSource

Ignore all requests