Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to merge two Consumer into one in Haskell Pipes?

Tags:

haskell

pipe

I use Haskell stream processing library pipes to write a command line tool. Each command line actions may output result to stdout and logs to stderr with pipes API.

I need Consumer which has type as Consumer (Either String String) m r to print chunk of data (Left to stderr, Right to stdout) with single Consumer.

Code I wrote (should be improved)

This function consumeEither doesn't have flexibility so I want to improve it.

consumeEither :: (MonadIO m) => Consumer (Either String String) m ()
consumeEither = do
  eitherS <- await
  case eitherS of
    (Left l)  -> for (yield l) (liftIO . (IO.hPutStrLn IO.stderr))
    (Right r) -> for (yiled r) (liftIO . putStrLn)

Furthermore it would be useful to provide a function which takes two Consumers and merge them into one Consumer.

Question

Does anybody know good example or implementation of the following interface?

merge :: (Monad m) => Consumer a m r -> Consumer b m r -> Consumer (Either a b) m r
  • 1st argument as stderr
  • 2nd argument as stdout

Usage of the function

import           Pipes
import qualified Pipes.Prelude as P
import qualified System.IO as IO

stdoutOrErr :: Consumer (Either String String) IO ()
stdoutOrErr = merge (P.toHandle IO.stderr) P.stdoutLn

Thanks

like image 612
ilyaletre Avatar asked Apr 29 '15 01:04

ilyaletre


1 Answers

(This is @Michael's answer, but I'd like to write it up here so we can move the question out of the unanswered queue for the Haskell tag.)

See (+++) in pipes-extras. Keep in mind a Consumer is a Pipe (to nowhere), so P.toHandle IO.stderr +++ P.stdoutLn :: MonadIO m => Pipe (Either String String) (Either b d) m ().

To get a Consumer, you would have to get rid of the Lefts e.g with >-> P.concat or >-> P.drain. There are more robust and handsome ways of doing this with Folds.

like image 165
hao Avatar answered Oct 21 '22 04:10

hao