Reputation: 524
In the code below how can I
change stdoutCharConsumer
so that it prints a newline after printing all the data from the input stream
implement mixin
and mixin'
without going into Pipes.Internal? Is it possible? I need someting like the next
function for Producers.
I use Pipes 4.1.0
#!/usr/bin/env runhaskell
{-# OPTIONS_GHC -Wall #-}
import Pipes
digits, characters :: Monad m => Producer Char m ()
digits = each "0123456789"
characters = each "abcdefghijklmnopqrstuvwxyz"
interleave :: Monad m => Producer a m () -> Producer a m () -> Producer a m ()
interleave a b = do
n <- lift $ next a
case n of
Left () -> b
Right (x, a') -> do
yield x
interleave b a'
stdoutCharConsumer :: Consumer Char IO ()
stdoutCharConsumer = await >>= liftIO . putChar >> stdoutCharConsumer
-- first element of the mixin should go first
mixin :: Monad m => Producer b m () -> Pipe a b m ()
mixin = undefined
-- first element of the pipe should go first
mixin' :: Monad m => Producer b m () -> Pipe a b m ()
mixin' = undefined
main :: IO ()
main = do
-- this prints "a0b1c2d3e4f5g6h7i8j9klmnopqrstuvwxyz"
runEffect $ interleave characters digits >-> stdoutCharConsumer
putStrLn ""
-- this prints "0a1b2c3d4e5f6g7h8i9jklmnopqrstuvwxyz"
runEffect $ interleave digits characters >-> stdoutCharConsumer
putStrLn ""
-- should print "0a1b2c3d4e5f6g7h8i9jklmnopqrstuvwxyz"
runEffect $ characters >-> mixin digits >-> stdoutCharConsumer
putStrLn ""
-- should print "a1b2c3d4e5f6g7h8i9jklmnopqrstuvwxyz"
runEffect $ digits >-> mixin characters >-> stdoutCharConsumer
putStrLn ""
-- should print "a1b2c3d4e5f6g7h8i9jklmnopqrstuvwxyz"
runEffect $ characters >-> mixin' digits >-> stdoutCharConsumer
putStrLn ""
-- should print "0a1b2c3d4e5f6g7h8i9jklmnopqrstuvwxyz"
runEffect $ digits >-> mixin' characters >-> stdoutCharConsumer
putStrLn ""
UPD: Now after I read about pull/pushs based streams I think it is impossible even with Pipes.Internal. Is it true?
Upvotes: 4
Views: 383
Reputation: 27756
Neither Consumers
nor Pipes
are aware of upstream end-of-input. You need Parser
s from pipes-parse
for that.
Compared to Consumer
s, Parser
s a more direct knowledge of Producer
s; their draw
function (roughly analogous to await
) returns a Nothing
when end-of-input is found.
import qualified Pipes.Parse as P
stdoutCharParser :: P.Parser Char IO ()
stdoutCharParser = P.draw >>= \ma ->
case ma of
Nothing -> liftIO (putStrLn "\n")
Just c -> liftIO (putChar c) >> stdoutCharParser
To run a parser, we invoke evalStateT
instead of runEffect
:
P.evalStateT stdoutCharParser (interleave characters digits)
As for mixin
and mixin'
, I suspect they will be impossible to write to work as intended. The reason is that the result Pipe
would have to be aware of upstream termination in order to know when to yield the remaining values of the Producer
passed as parameter.
Upvotes: 3