@Michael's answer is good. I just want to illustrate some
usage patterns that are going on here.
( .lhs available at http://lpaste.net/165352 )
First a few imports:
{-# LANGUAGE OverloadedStrings, NoMonomorphismRestriction #-}
import Pipes
import qualified Pipes.Prelude as PP
import qualified Pipes.Group as PG
import qualified Pipes.ByteString as PB
import qualified Pipes.GZip as GZip
import qualified Data.ByteString as BS
import Lens.Family (view, over)
import Control.Monad
import System.IO
If you look over the functions in Pipes.ByteString and Pipes.GZip
you'll see that they all into the following type schemas:
- Producer ... -> FreeT (Producer ...) ...
- FreeT (Producer ...) ... -> Producer ...
- Lens' (Producer ...) (FreeT (Producer ...) ...)
- Producer ... -> Producer ...
Examples of functions in each category:
PB.words
PG.concats
PB.lines
, PB.chunksOf
, PB.splits
, ...
GZip.compress
, GZip.decompress
Here's how to use PB.words
to split an input stream into words:
prod = yield "this is\na test\nof the pipes\nprocessing\nsystem"
t1 = runEffect $ (PG.concats . PB.words) prod >-> PP.print
To use a function of type 3 -- e.g. PB.lines
, just use view
on the
Lens'
to get a function of type 1 and then compose with PG.concats
:
t2a = runEffect $ (PG.concats . view PB.lines) prod >-> PP.print
t2b h = (PG.concats . view PB.lines) (PB.fromHandle h) >-> PP.print
run2 = withFile "input" ReadMode (runEffect . t2b)
For a Producer -> Producer function, just use normal function application:
t3 h = GZip.decompress (PB.fromHandle h) >-> PP.print
run3 = withFile "input.gz" ReadMode (runEffect . t3)
t4 h = GZip.decompress (PB.fromHandle h) >-> PP.map BS.length >-> PP.print
run4 = withFile "big.gz" ReadMode (runEffect . t4)
To first decompress and then split by lines, we nest function
application:
t5 h = (PG.concats . view PB.lines) ( GZip.decompress (PB.fromHandle h) )
>-> PP.map BS.length >-> PP.print
run5 = withFile "input.gz" ReadMode (runEffect . t5)