Pipes.Prelude

pipes-4.1.8: Compositional pipelines

Safe Haskell | Trustworthy
Language | Haskell2010

Pipes.Prelude

Contents

- Producers
- Consumers
- Pipes
- ListT
- Folds
- Zips
- Utilities

Description

General purpose utilities

The names in this module clash heavily with the Haskell Prelude, so I recommend the following import scheme:

    import Pipes
    import qualified Pipes.Prelude as P  -- or use any other qualifier you prefer

Note that `String`-based `IO` is inefficient. The `String`-based utilities in this module exist only for simple demonstrations without incurring a dependency on the `text` package.

Also, `stdinLn` and `stdoutLn` remove and add newlines, respectively. This behavior is intended to simplify examples. The corresponding `stdin` and `stdout` utilities from `pipes-bytestring` and `pipes-text` preserve newlines.

Synopsis

- stdinLn :: MonadIO m => Producer' String m ()
- readLn :: (MonadIO m, Read a) => Producer' a m ()
- fromHandle :: MonadIO m => Handle -> Producer' String m ()
- repeatM :: Monad m => m a -> Producer' a m r
- replicateM :: Monad m => Int -> m a -> Producer' a m ()
- unfoldr :: Monad m => (s -> m (Either r (a, s))) -> s -> Producer a m r
- stdoutLn :: MonadIO m => Consumer' String m ()
- stdoutLn' :: MonadIO m => Consumer' String m r
- mapM_ :: Monad m => (a -> m ()) -> Consumer' a m r
- print :: (MonadIO m, Show a) => Consumer' a m r
- toHandle :: MonadIO m => Handle -> Consumer' String m r
- drain :: Monad m => Consumer' a m r
- map :: Monad m => (a -> b) -> Pipe a b m r
- mapM :: Monad m => (a -> m b) -> Pipe a b m r
- sequence :: Monad m => Pipe (m a) a m r
- mapFoldable :: (Monad m, Foldable t) => (a -> t b) -> Pipe a b m r
- filter :: Monad m => (a -> Bool) -> Pipe a a m r
- filterM :: Monad m => (a -> m Bool) -> Pipe a a m r
- take :: Monad m => Int -> Pipe a a m ()
- takeWhile :: Monad m => (a -> Bool) -> Pipe a a m ()
- takeWhile' :: Monad m => (a -> Bool) -> Pipe a a m a
- drop :: Monad m => Int -> Pipe a a m r
- dropWhile :: Monad m => (a -> Bool) -> Pipe a a m r
- concat :: (Monad m, Foldable f) => Pipe (f a) a m r
- elemIndices :: (Monad m, Eq a) => a -> Pipe a Int m r
- findIndices :: Monad m => (a -> Bool) -> Pipe a Int m r
- scan :: Monad m => (x -> a -> x) -> x -> (x -> b) -> Pipe a b m r
- scanM :: Monad m => (x -> a -> m x) -> m x -> (x -> m b) -> Pipe a b m r
- chain :: Monad m => (a -> m ()) -> Pipe a a m r
- read :: (Monad m, Read a) => Pipe String a m r
- show :: (Monad m, Show a) => Pipe a String m r
- seq :: Monad m => Pipe a a m r
- loop :: Monad m => (a -> ListT m b) -> Pipe a b m r
- fold :: Monad m => (x -> a -> x) -> x -> (x -> b) -> Producer a m () -> m b
- fold' :: Monad m => (x -> a -> x) -> x -> (x -> b) -> Producer a m r -> m (b, r)
- foldM :: Monad m => (x -> a -> m x) -> m x -> (x -> m b) -> Producer a m () -> m b
- foldM' :: Monad m => (x -> a -> m x) -> m x -> (x -> m b) -> Producer a m r -> m (b, r)
- all :: Monad m => (a -> Bool) -> Producer a m () -> m Bool
- any :: Monad m => (a -> Bool) -> Producer a m () -> m Bool
- and :: Monad m => Producer Bool m () -> m Bool
- or :: Monad m => Producer Bool m () -> m Bool
- elem :: (Monad m, Eq a) => a -> Producer a m () -> m Bool
- notElem :: (Monad m, Eq a) => a -> Producer a m () -> m Bool
- find :: Monad m => (a -> Bool) -> Producer a m () -> m (Maybe a)
- findIndex :: Monad m => (a -> Bool) -> Producer a m () -> m (Maybe Int)
- head :: Monad m => Producer a m () -> m (Maybe a)
- index :: Monad m => Int -> Producer a m () -> m (Maybe a)
- last :: Monad m => Producer a m () -> m (Maybe a)
- length :: Monad m => Producer a m () -> m Int
- maximum :: (Monad m, Ord a) => Producer a m () -> m (Maybe a)
- minimum :: (Monad m, Ord a) => Producer a m () -> m (Maybe a)
- null :: Monad m => Producer a m () -> m Bool
- sum :: (Monad m, Num a) => Producer a m () -> m a
- product :: (Monad m, Num a) => Producer a m () -> m a
- toList :: Producer a Identity () -> [a]
- toListM :: Monad m => Producer a m () -> m [a]
- toListM' :: Monad m => Producer a m r -> m ([a], r)
- zip :: Monad m => Producer a m r -> Producer b m r -> Producer' (a, b) m r
- zipWith :: Monad m => (a -> b -> c) -> Producer a m r -> Producer b m r -> Producer' c m r
- tee :: Monad m => Consumer a m r -> Pipe a a m r
- generalize :: Monad m => Pipe a b m r -> x -> Proxy x a x b m r

# Producers

Use `for` loops to iterate over `Producer`s whenever you want to perform the same action for every element:

    -- Echo all lines from standard input to standard output
    runEffect $ for P.stdinLn $ \str -> do
        lift $ putStrLn str

... or more concisely:

    >>> runEffect $ for P.stdinLn (lift . putStrLn)
    Test<Enter>
    Test
    ABC<Enter>
    ABC
    ...

stdinLn :: MonadIO m => Producer' String m ()

Read `String`s from `stdin` using `getLine`

Terminates on end of input

readLn :: (MonadIO m, Read a) => Producer' a m ()

`read` values from `stdin`, ignoring failed parses

fromHandle :: MonadIO m => Handle -> Producer' String m ()

Read `String`s from a `Handle` using `hGetLine`

Terminates on end of input

repeatM :: Monad m => m a -> Producer' a m r

Repeat a monadic action indefinitely, `yield`ing each result

replicateM :: Monad m => Int -> m a -> Producer' a m ()

Repeat a monadic action a fixed number of times, `yield`ing each result

    replicateM  0      x = return ()

    replicateM (m + n) x = replicateM m x >> replicateM n x  -- 0 <= {m,n}

unfoldr :: Monad m => (s -> m (Either r (a, s))) -> s -> Producer a m r

The natural unfold into a `Producer` with a step function and a seed

    unfoldr next = id

# Consumers

Feed a `Consumer` the same value repeatedly using (`>~`):

    >>> runEffect $ lift getLine >~ P.stdoutLn
    Test<Enter>
    Test
    ABC<Enter>
    ABC
    ...

stdoutLn :: MonadIO m => Consumer' String m ()

Write `String`s to `stdout` using `putStrLn`

Unlike `toHandle`, `stdoutLn` gracefully terminates on a broken output pipe

stdoutLn' :: MonadIO m => Consumer' String m r

Write `String`s to `stdout` using `putStrLn`

This does not handle a broken output pipe, but has a polymorphic return value

mapM_ :: Monad m => (a -> m ()) -> Consumer' a m r

Consume all values using a monadic function

print :: (MonadIO m, Show a) => Consumer' a m r

`print` values to `stdout`

toHandle :: MonadIO m => Handle -> Consumer' String m r

Write `String`s to a `Handle` using `hPutStrLn`

drain :: Monad m => Consumer' a m r

`discard` all incoming values

# Pipes

Use (`>->`) to connect `Producer`s, `Pipe`s, and `Consumer`s:

    >>> runEffect $ P.stdinLn >-> P.takeWhile (/= "quit") >-> P.stdoutLn
    Test<Enter>
    Test
    ABC<Enter>
    ABC
    quit<Enter>
    >>>

map :: Monad m => (a -> b) -> Pipe a b m r

Apply a function to all values flowing downstream

    map id = cat

    map (g . f) = map f >-> map g

mapM :: Monad m => (a -> m b) -> Pipe a b m r

Apply a monadic function to all values flowing downstream

    mapM return = cat

    mapM (f >=> g) = mapM f >-> mapM g

sequence :: Monad m => Pipe (m a) a m r

Convert a stream of actions to a stream of values

mapFoldable :: (Monad m, Foldable t) => (a -> t b) -> Pipe a b m r

Apply a function to all values flowing downstream, and forward each element of the result.

filter :: Monad m => (a -> Bool) -> Pipe a a m r

`(filter predicate)` only forwards values that satisfy the predicate.

    filter (pure True) = cat

    filter (liftA2 (&&) p1 p2) = filter p1 >-> filter p2

filterM :: Monad m => (a -> m Bool) -> Pipe a a m r

`(filterM predicate)` only forwards values that satisfy the monadic predicate

    filterM (pure (pure True)) = cat

    filterM (liftA2 (liftA2 (&&)) p1 p2) = filterM p1 >-> filterM p2

take :: Monad m => Int -> Pipe a a m ()

`(take n)` only allows `n` values to pass through

    take 0 = return ()

    take (m + n) = take m >> take n

    take <infinity> = cat

    take (min m n) = take m >-> take n

takeWhile :: Monad m => (a -> Bool) -> Pipe a a m ()

`(takeWhile p)` allows values to pass downstream so long as they satisfy the predicate `p`.

    takeWhile (pure True) = cat

    takeWhile (liftA2 (&&) p1 p2) = takeWhile p1 >-> takeWhile p2

takeWhile' :: Monad m => (a -> Bool) -> Pipe a a m a

`(takeWhile' p)` is a version of takeWhile that returns the value failing the predicate.

    takeWhile' (pure True) = cat

    takeWhile' (liftA2 (&&) p1 p2) = takeWhile' p1 >-> takeWhile' p2

drop :: Monad m => Int -> Pipe a a m r

`(drop n)` discards `n` values going downstream

    drop 0 = cat

    drop (m + n) = drop m >-> drop n

dropWhile :: Monad m => (a -> Bool) -> Pipe a a m r

`(dropWhile p)` discards values going downstream until one violates the predicate `p`.

    dropWhile (pure False) = cat

    dropWhile (liftA2 (||) p1 p2) = dropWhile p1 >-> dropWhile p2

concat :: (Monad m, Foldable f) => Pipe (f a) a m r

Flatten all `Foldable` elements flowing downstream

elemIndices :: (Monad m, Eq a) => a -> Pipe a Int m r

Outputs the indices of all elements that match the given element

findIndices :: Monad m => (a -> Bool) -> Pipe a Int m r

Outputs the indices of all elements that satisfied the predicate

scan :: Monad m => (x -> a -> x) -> x -> (x -> b) -> Pipe a b m r

Strict left scan

    Control.Foldl.purely scan :: Monad m => Fold a b -> Pipe a b m r

scanM :: Monad m => (x -> a -> m x) -> m x -> (x -> m b) -> Pipe a b m r

Strict, monadic left scan

    Control.Foldl.impurely scan :: Monad m => FoldM a m b -> Pipe a b m r

chain :: Monad m => (a -> m ()) -> Pipe a a m r

Apply an action to all values flowing downstream

    chain (pure (return ())) = cat

    chain (liftA2 (>>) m1 m2) = chain m1 >-> chain m2

read :: (Monad m, Read a) => Pipe String a m r

Parse `Read`able values, only forwarding the value if the parse succeeds

show :: (Monad m, Show a) => Pipe a String m r

Convert `Show`able values to `String`s

seq :: Monad m => Pipe a a m r

Evaluate all values flowing downstream to WHNF

# ListT

loop :: Monad m => (a -> ListT m b) -> Pipe a b m r

Create a `Pipe` from a `ListT` transformation

    loop (k1 >=> k2) = loop k1 >-> loop k2

    loop return = cat

# Folds

Use these to fold the output of a `Producer`. Many of these folds will stop drawing elements if they can compute their result early, like `any`:

    >>> P.any null P.stdinLn
    Test<Enter>
    ABC<Enter>
    <Enter>
    True
    >>>

fold :: Monad m => (x -> a -> x) -> x -> (x -> b) -> Producer a m () -> m b

Strict fold of the elements of a `Producer`

    Control.Foldl.purely fold :: Monad m => Fold a b -> Producer a m () -> m b

fold' :: Monad m => (x -> a -> x) -> x -> (x -> b) -> Producer a m r -> m (b, r)

Strict fold of the elements of a `Producer` that preserves the return value

    Control.Foldl.purely fold' :: Monad m => Fold a b -> Producer a m r -> m (b, r)

foldM :: Monad m => (x -> a -> m x) -> m x -> (x -> m b) -> Producer a m () -> m b

Strict, monadic fold of the elements of a `Producer`

    Control.Foldl.impurely foldM :: Monad m => FoldM a b -> Producer a m () -> m b

foldM' :: Monad m => (x -> a -> m x) -> m x -> (x -> m b) -> Producer a m r -> m (b, r)

Strict, monadic fold of the elements of a `Producer`

    Control.Foldl.impurely foldM' :: Monad m => FoldM a b -> Producer a m r -> m (b, r)

all :: Monad m => (a -> Bool) -> Producer a m () -> m Bool

`(all predicate p)` determines whether all the elements of `p` satisfy the predicate.

any :: Monad m => (a -> Bool) -> Producer a m () -> m Bool

`(any predicate p)` determines whether any element of `p` satisfies the predicate.

and :: Monad m => Producer Bool m () -> m Bool

Determines whether all elements are `True`

or :: Monad m => Producer Bool m () -> m Bool

Determines whether any element is `True`

elem :: (Monad m, Eq a) => a -> Producer a m () -> m Bool

`(elem a p)` returns `True` if `p` has an element equal to `a`, `False` otherwise

notElem :: (Monad m, Eq a) => a -> Producer a m () -> m Bool

`(notElem a)` returns `False` if `p` has an element equal to `a`, `True` otherwise

find :: Monad m => (a -> Bool) -> Producer a m () -> m (Maybe a)

Find the first element of a `Producer` that satisfies the predicate

findIndex :: Monad m => (a -> Bool) -> Producer a m () -> m (Maybe Int)

Find the index of the first element of a `Producer` that satisfies the predicate

head :: Monad m => Producer a m () -> m (Maybe a)

Retrieve the first element from a `Producer`

index :: Monad m => Int -> Producer a m () -> m (Maybe a)

Index into a `Producer`

last :: Monad m => Producer a m () -> m (Maybe a)

Retrieve the last element from a `Producer`

length :: Monad m => Producer a m () -> m Int

Count the number of elements in a `Producer`

maximum :: (Monad m, Ord a) => Producer a m () -> m (Maybe a)

Find the maximum element of a `Producer`

minimum :: (Monad m, Ord a) => Producer a m () -> m (Maybe a)

Find the minimum element of a `Producer`

null :: Monad m => Producer a m () -> m Bool

Determine if a `Producer` is empty

sum :: (Monad m, Num a) => Producer a m () -> m a

Compute the sum of the elements of a `Producer`

product :: (Monad m, Num a) => Producer a m () -> m a

Compute the product of the elements of a `Producer`

toList :: Producer a Identity () -> [a]

Convert a pure `Producer` into a list

toListM :: Monad m => Producer a m () -> m [a]

Convert an effectful `Producer` into a list

Note: `toListM` is not an idiomatic use of `pipes`, but I provide it for simple testing purposes. Idiomatic `pipes` style consumes the elements immediately as they are generated instead of loading all elements into memory.

toListM' :: Monad m => Producer a m r -> m ([a], r)

Convert an effectful `Producer` into a list alongside the return value

Note: `toListM'` is not an idiomatic use of `pipes`, but I provide it for simple testing purposes. Idiomatic `pipes` style consumes the elements immediately as they are generated instead of loading all elements into memory.

# Zips

zip :: Monad m => Producer a m r -> Producer b m r -> Producer' (a, b) m r

Zip two `Producer`s

zipWith :: Monad m => (a -> b -> c) -> Producer a m r -> Producer b m r -> Producer' c m r

Zip two `Producer`s using the provided combining function

# Utilities

tee :: Monad m => Consumer a m r -> Pipe a a m r

Transform a `Consumer` to a `Pipe` that reforwards all values further downstream

generalize :: Monad m => Pipe a b m r -> x -> Proxy x a x b m r

Transform a unidirectional `Pipe` to a bidirectional `Proxy`

    generalize (f >-> g) = generalize f >+> generalize g

    generalize cat = pull