pipes-3.0.0: Compositional pipelines

Safe HaskellSafe
LanguageHaskell98

Control.Pipe

Contents

Description

This module remains as a wistful reminder of this library's humble origins. This library now builds upon the more general Proxy type, but still keeps the pipes name. Read Control.Proxy.Tutorial to learn about this new implementation.

The Pipe type is a monad transformer that enriches the base monad with the ability to await or yield data to and from other Pipes.

Synopsis

Types

The Pipe type is strongly inspired by Mario Blazevic's Coroutine type in his concurrency article from Issue 19 of The Monad Reader.

data Pipe a b m r Source #

The base type for pipes

  • a - The type of input received from upstream pipes
  • b - The type of output delivered to downstream pipes
  • m - The base monad
  • r - The type of the return value

Constructors

Await (a -> Pipe a b m r) 
Yield b (Pipe a b m r) 
M (m (Pipe a b m r)) 
Pure r 

Instances

MonadTrans (Pipe a b) Source # 

Methods

lift :: Monad m => m a -> Pipe a b m a #

Monad m => Monad (Pipe a b m) Source # 

Methods

(>>=) :: Pipe a b m a -> (a -> Pipe a b m b) -> Pipe a b m b #

(>>) :: Pipe a b m a -> Pipe a b m b -> Pipe a b m b #

return :: a -> Pipe a b m a #

fail :: String -> Pipe a b m a #

Monad m => Functor (Pipe a b m) Source # 

Methods

fmap :: (a -> b) -> Pipe a b m a -> Pipe a b m b #

(<$) :: a -> Pipe a b m b -> Pipe a b m a #

Monad m => Applicative (Pipe a b m) Source # 

Methods

pure :: a -> Pipe a b m a #

(<*>) :: Pipe a b m (a -> b) -> Pipe a b m a -> Pipe a b m b #

(*>) :: Pipe a b m a -> Pipe a b m b -> Pipe a b m b #

(<*) :: Pipe a b m a -> Pipe a b m b -> Pipe a b m a #

type Producer b m r = Pipe () b m r Source #

A pipe that produces values

type Consumer a m r = Pipe a C m r Source #

A pipe that consumes values

type Pipeline m r = Pipe () C m r Source #

A self-contained pipeline that is ready to be run

Create Pipes

yield and await are the only two primitives you need to create pipes. Since Pipe a b m is a monad, you can assemble yield and await statements using ordinary do notation. Since Pipe a b is also a monad transformer, you can use lift to invoke the base monad. For example, you could write a pipe stage that requests permission before forwarding any output:

check :: (Show a) => Pipe a a IO r
check = forever $ do
    x <- await
    lift $ putStrLn $ "Can '" ++ (show x) ++ "' pass?"
    ok <- read <$> lift getLine
    when ok (yield x)

await :: Pipe a b m a Source #

Wait for input from upstream.

await blocks until input is available from upstream.

yield :: b -> Pipe a b m () Source #

Deliver output downstream.

yield restores control back upstream and binds its value to await.

pipe :: Monad m => (a -> b) -> Pipe a b m r Source #

Convert a pure function into a pipe

pipe f = forever $ do
    x <- await
    yield (f x)

Compose Pipes

Pipes form a Category, meaning that you can compose Pipes using (>+>) and also define an identity Pipe: idP. These satisfy the category laws:

idP >+> p = p

p >+> idP = p

(p1 >+> p2) >+> p3 = p1 >+> (p2 >+> p3)

(p1 >+> p2) satisfies all awaits in p2 with yields in p1. If any Pipe terminates the entire Pipeline terminates.

(<+<) :: Monad m => Pipe b c m r -> Pipe a b m r -> Pipe a c m r infixr 8 Source #

Corresponds to (<<<)/(.) from Control.Category

(>+>) :: Monad m => Pipe a b m r -> Pipe b c m r -> Pipe a c m r infixl 8 Source #

Corresponds to (>>>) from Control.Category

idP :: Monad m => Pipe a a m r Source #

Corresponds to id from Control.Category

newtype PipeC m r a b Source #

Pipes form a Category instance when you rearrange the type variables

Constructors

PipeC 

Fields

Instances

Monad m => Category * (PipeC m r) Source # 

Methods

id :: cat a a #

(.) :: cat b c -> cat a b -> cat a c #

Run Pipes

runPipe :: Monad m => Pipe () b m r -> m r Source #

Run the Pipe monad transformer, converting it back into the base monad