HORIZON HASKELLDocslts/ghc-9.10.xc74966e2026-09-27Search names, modules, packages, or :: a typeCtrl K

GHC 9.10.3 · lts/ghc-9.10.x · c74966e · 2026-09-27

Modulepipes-4.3.16Haskell2010

Pipes

This module is the recommended entry point to the pipes library.

Read Pipes.Tutorial if you want a tutorial explaining how to use this library.

  • 10 types
  • 7 classes
  • 17 values
  • Packagepipes-4.3.16
  • Exports34
  • LanguageHaskell2010
  • LicenceBSD-3-Clause
  • SourcePipes.hs

The Proxy Monad Transformer

5 declarations
datadata Proxy a' a b' b (m :: Type -> Type) 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

Instances16MFunctor, MonadError, MonadReader, MonadState, MonadWriter, MonadTrans, …
typetype X = Void
#

The empty type, used to close output ends

Producers

Use yield to produce output and (~>) / for to substitute yields.

yield and (~>) obey the Category laws:

-- Substituting 'yield' with 'f' gives 'f'
yield ~> f = f

-- Substituting every 'yield' with another 'yield' does nothing
f ~> yield = f

-- 'yield' substitution is associative
(f ~> g) ~> h = f ~> (g ~> h)

These are equivalent to the following "for loop laws":

-- Looping over a single yield simplifies to function application
for (yield x) f = f x

-- Re-yielding every element of a stream returns the original stream
for s yield = s

-- Nested for loops can become a sequential for loops if the inner loop
-- body ignores the outer loop variable
for s (\a -> for (f a) g) = for (for s f) g = for s (f ~> g)
valuefor
  1. :: Functor m
  2. => Proxy x' x b' b m a'
  3. -> b -> Proxy x' x c' c m b'
  4. -> Proxy x' x c' c m a'
#

(for p body) loops over p replacing each yield with body.

for :: Functor m => Producer b m r -> (b -> Effect       m ()) -> Effect       m r
for :: Functor m => Producer b m r -> (b -> Producer   c m ()) -> Producer   c m r
for :: Functor m => Pipe   x b m r -> (b -> Consumer x   m ()) -> Consumer x   m r
for :: Functor m => Pipe   x b m r -> (b -> Pipe     x c m ()) -> Pipe     x c m r

The following diagrams show the flow of information:

                              .--->   b
                             /        |
   +-----------+            /   +-----|-----+                 +---------------+
   |           |           /    |     v     |                 |               |
   |           |          /     |           |                 |               |
x ==>    p    ==> b   ---'   x ==>   body  ==> c     =     x ==> for p body  ==> c
   |           |                |           |                 |               |
   |     |     |                |     |     |                 |       |       |
   +-----|-----+                +-----|-----+                 +-------|-------+
         v                            v                               v
         r                            ()                              r

For a more complete diagram including bidirectional flow, see Pipes.Core#respond-diagram.

value(~>)
  1. :: Functor m
  2. => a -> Proxy x' x b' b m a'
  3. -> b -> Proxy x' x c' c m b'
  4. -> a
  5. -> Proxy x' x c' c m a'
#

Compose loop bodies

(~>) :: Functor m => (a -> Producer b m r) -> (b -> Effect       m ()) -> (a -> Effect       m r)
(~>) :: Functor m => (a -> Producer b m r) -> (b -> Producer   c m ()) -> (a -> Producer   c m r)
(~>) :: Functor m => (a -> Pipe   x b m r) -> (b -> Consumer x   m ()) -> (a -> Consumer x   m r)
(~>) :: Functor m => (a -> Pipe   x b m r) -> (b -> Pipe     x c m ()) -> (a -> Pipe     x c m r)

The following diagrams show the flow of information:

         a                    .--->   b                              a
         |                   /        |                              |
   +-----|-----+            /   +-----|-----+                 +------|------+
   |     v     |           /    |     v     |                 |      v      |
   |           |          /     |           |                 |             |
x ==>    f    ==> b   ---'   x ==>    g    ==> c     =     x ==>   f ~> g  ==> c
   |           |                |           |                 |             |
   |     |     |                |     |     |                 |      |      |
   +-----|-----+                +-----|-----+                 +------|------+
         v                            v                              v
         r                            ()                             r

For a more complete diagram including bidirectional flow, see Pipes.Core#respond-diagram.

value(<~)
  1. :: Functor m
  2. => b -> Proxy x' x c' c m b'
  3. -> a -> Proxy x' x b' b m a'
  4. -> a
  5. -> Proxy x' x c' c m a'
#

(~>) with the arguments flipped

Consumers

Use await to request input and (>~) to substitute awaits.

await and (>~) obey the Category laws:

-- Substituting every 'await' with another 'await' does nothing
await >~ f = f

-- Substituting 'await' with 'f' gives 'f'
f >~ await = f

-- 'await' substitution is associative
(f >~ g) >~ h = f >~ (g >~ h)
value(>~)
  1. :: Functor m
  2. => Proxy a' a y' y m b
  3. -> Proxy () b y' y m c
  4. -> Proxy a' a y' y m c
#

(draw >~ p) loops over p replacing each await with draw

(>~) :: Functor m => Effect       m b -> Consumer b   m c -> Effect       m c
(>~) :: Functor m => Consumer a   m b -> Consumer b   m c -> Consumer a   m c
(>~) :: Functor m => Producer   y m b -> Pipe     b y m c -> Producer   y m c
(>~) :: Functor m => Pipe     a y m b -> Pipe     b y m c -> Pipe     a y m c

The following diagrams show the flow of information:

   +-----------+                 +-----------+                 +-------------+
   |           |                 |           |                 |             |
   |           |                 |           |                 |             |
a ==>    f    ==> y   .--->   b ==>    g    ==> y     =     a ==>   f >~ g  ==> y
   |           |     /           |           |                 |             |
   |     |     |    /            |     |     |                 |      |      |
   +-----|-----+   /             +-----|-----+                 +------|------+
         v        /                    v                              v
         b   ----'                     c                              c

For a more complete diagram including bidirectional flow, see Pipes.Core#request-diagram.

Pipes

Use await and yield to build Pipes and (>->) to connect Pipes.

cat and (>->) obey the Category laws:

-- Useless use of cat
cat >-> f = f

-- Redirecting output to cat does nothing
f >-> cat = f

-- The pipe operator is associative
(f >-> g) >-> h = f >-> (g >-> h)
valuecat :: Functor m => Pipe a a m r
#

The identity Pipe, analogous to the Unix cat program

value(>->)
  1. :: Functor m
  2. => Proxy a' a () b m r
  3. -> Proxy () b c' c m r
  4. -> Proxy a' a c' c m r
#

Pipe composition, analogous to the Unix pipe operator

(>->) :: Functor m => Producer b m r -> Consumer b   m r -> Effect       m r
(>->) :: Functor m => Producer b m r -> Pipe     b c m r -> Producer   c m r
(>->) :: Functor m => Pipe   a b m r -> Consumer b   m r -> Consumer a   m r
(>->) :: Functor m => Pipe   a b m r -> Pipe     b c m r -> Pipe     a c m r

The following diagrams show the flow of information:

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

For a more complete diagram including bidirectional flow, see Pipes.Core#pull-diagram.

ListT

3 declarations
newtypenewtype ListT (m :: Type -> Type) a
#

The list monad transformer, which extends a monad with non-determinism

The type variables signify:

  • m - The base monad

  • a - The values that the computation yields throughout its execution

For basic construction and composition of ListT computations, much can be accomplished using common typeclass methods.

  • return corresponds to yield, yielding a single value.

  • (>>=) corresponds to for, calling the second computation once for each time the first computation yields.

  • mempty neither yields any values nor produces any effects in the base monad.

  • (<>) sequences two computations, yielding all the values of the first followed by all the values of the second.

  • lift converts an action in the base monad into a ListT computation which performs the action and yields a single value.

ListT is a newtype wrapper for Producer. You will likely need to use Select and enumerate to convert back and forth between these two types to take advantage of all the Producer-related utilities that Pipes.Prelude has to offer.

Constructors

Instances22MonadTrans, MMonad, Enumerable, MFunctor, MonadError, MonadReader, …
classclass Enumerable (t :: (Type -> Type) -> Type -> Type) where
#

Enumerable generalizes Foldable, converting effectful containers to ListTs.

Instances of Enumerable must satisfy these two laws:

toListT (return r) = return r

toListT $ do x <- m  =  do x <- toListT m
             f x           toListT (f x)

In other words, toListT is monad morphism.

Methods

Instances4Enumerable

Utilities

4 declarations

Re-exports

7 declarations

Control.Monad re-exports void

Control.Monad.IO.Class re-exports MonadIO.

Control.Monad.Trans.Class re-exports MonadTrans.

Control.Monad.Morph re-exports MFunctor.

Data.Foldable re-exports Foldable (the class name only).

valuevoid :: Functor f => f a -> f ()
#

void value discards or ignores the result of evaluation, such as the return value of an System.IO.IO action.

Examples

Replace the contents of a Maybe Int with unit:

Example1 expression
void NothingNothing
Example1 expression
void (Just 3)Just ()

Replace the contents of an Either Int Int with unit, resulting in an Either Int ():

Example1 expression
void (Left 8675309)Left 8675309
Example1 expression
void (Right 8675309)Right ()

Replace every element of a list with unit:

Example1 expression
void [1,2,3][(),(),()]

Replace the second element of a pair with unit:

Example1 expression
void (1,2)(1,())

Discard the result of an System.IO.IO action:

Example1 expression
mapM print [1,2]12[(),()]
Example1 expression
void $ mapM print [1,2]12
classclass (Alternative m, Monad m) => MonadPlus (m :: Type -> Type) where
#

Monads that also support choice and failure.

Methods

  • mzero :: m a

    The identity of mplus. It should also satisfy the equations

    mzero >>= f  =  mzero
    v >> mzero   =  mzero

    The default definition is

    mzero = empty
    
  • mplus :: m a -> m a -> m a

    An associative operation. The default definition is

    mplus = (<|>)
    
Instances35MonadPlus, …
classclass Monad m => MonadIO (m :: Type -> Type) where
#

Monads in which IO computations may be embedded. Any monad built by applying a sequence of monad transformers to the IO monad will be an instance of this class.

Instances should satisfy the following laws, which state that liftIO is a transformer of monads:

Methods

  • liftIO :: IO a -> m a

    Lift a computation from the IO monad. This allows us to run IO computations in any monadic stack, so long as it supports these kinds of operations (i.e. IO is the base monad for the stack).

    Example
    import Control.Monad.Trans.State -- from the "transformers" library
    
    printState :: Show s => StateT s IO ()
    printState = do
      state <- get
      liftIO $ print state

    Had we omitted liftIO, we would have ended up with this error:

    • Couldn't match type ‘IO’ with ‘StateT s IO’
     Expected type: StateT s IO ()
       Actual type: IO ()

    The important part here is the mismatch between StateT s IO () and IO ().

    Luckily, we know of a function that takes an IO a and returns an (m a): liftIO, enabling us to run the program and see the expected results:

    > evalStateT printState "hello"
    "hello"
    
    > evalStateT printState 3
    3
    
Instances21MonadIO, …
classclass (forall (m :: Type -> Type). Monad m => Monad (t m)) => MonadTrans (t :: (Type -> Type) -> Type -> Type) where
#

The class of monad transformers. For any monad m, the result t m should also be a monad, and lift should be a monad transformation from m to t m, i.e. it should satisfy the following laws:

Since 0.6.0.0 and for GHC 8.6 and later, the requirement that t m be a Monad is enforced by the implication constraint forall m. Monad m => Monad (t m) enabled by the QuantifiedConstraints extension.

Ambiguity error with GHC 9.0 to 9.2.2

These versions of GHC have a bug (https://gitlab.haskell.org/ghc/ghc/-/issues/20582) which causes constraints like

(MonadTrans t, forall m. Monad m => Monad (t m)) => ...

to be reported as ambiguous. For transformers 0.6 and later, this can be fixed by removing the second constraint, which is implied by the first.

Methods

  • lift :: Monad m => m a -> t m a

    Lift a computation from the argument monad to the constructed monad.

Instances19MonadTrans, …
classclass MFunctor (t :: (Type -> Type) -> k -> Type) where
#

A functor in the category of monads, using hoist as the analog of fmap:

hoist (f . g) = hoist f . hoist g

hoist id = id

Methods

  • hoist :: Monad m => (forall a. m a -> n a) -> t m b -> t n b

    Lift a monad morphism from m to n into a monad morphism from (t m) to (t n)

    The first argument to hoist must be a monad morphism, even though the type system does not enforce this

Instances18MFunctor, …
classclass (MFunctor t, MonadTrans t) => MMonad (t :: (Type -> Type) -> Type -> Type) where
#

A monad in the category of monads, using lift from MonadTrans as the analog of return and embed as the analog of (=<<):

embed lift = id

embed f (lift m) = f m

embed g (embed f t) = embed (\m -> embed g (f m)) t

Methods

  • embed :: Monad n => (forall a. m a -> t n a) -> t m b -> t n b

    Embed a newly created MMonad layer within an existing layer

    embed is analogous to (=<<)

Instances9MMonad, …
classclass Foldable (t :: Type -> Type) where
#

The Foldable class represents data structures that can be reduced to a summary value one element at a time. Strict left-associative folds are a good fit for space-efficient reduction, while lazy right-associative folds are a good fit for corecursive iteration, or for folds that short-circuit after processing an initial subsequence of the structure's elements.

Instances can be derived automatically by enabling the DeriveFoldable extension. For example, a derived instance for a binary tree might be:

{-# LANGUAGE DeriveFoldable #-}
data Tree a = Empty
            | Leaf a
            | Node (Tree a) a (Tree a)
    deriving Foldable

A more detailed description can be found in the Overview section of Data.Foldable#overview.

For the class laws see the Laws section of Data.Foldable#laws.

Instances56Foldable, …