11

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

ilyaletre
  • 111
  • 4
  • I think you need the [`ArrowChoice` proxies](http://hackage.haskell.org/package/pipes-3.2.0/docs/Control-Proxy-Prelude-Base.html#g:7). [Some discussion here](http://www.haskellforall.com/2013/03/pipes-32-listt-codensity-arrowchoice.html) – rampion Apr 29 '15 at 01:38
  • 2
    See `(+++)` in [pipes-extras](http://hackage.haskell.org/package/pipes-extras-1.0.0/docs/Pipes-Extras.html#g:1) 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 `Left`s e.g with `>-> P.concat` or `>-> P.drain` There are more robust and handsome ways of doing this with Folds. – Michael Apr 29 '15 at 03:21
  • Sorry, maybe that was more confusing than: `merge p q = p +++ q >-> P.concat` . (Here, `P.concat` is acting like `Data.Either.rights`) – Michael Apr 29 '15 at 03:47
  • @rampion I found out that what I want to do is not "merging consumers" but "choose consumers". You gave me the point. I'll check it. Thanks. – ilyaletre Apr 29 '15 at 10:46
  • @Michael concise combinator +++! It looks useful. I'll try it. Thanks. – ilyaletre Apr 29 '15 at 10:49
  • 1
    @Michael would you like to write that up as an answer? :P – Lambda Fairy Aug 16 '15 at 01:26

1 Answers1

1

(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.

hao
  • 10,138
  • 1
  • 35
  • 50