Как объединить двух потребителей в один в Haskell Pipes?
Я использую библиотеку обработки потока Haskell pipes, чтобы написать инструмент командной строки. Каждое действие в командной строке может выводить результат в stdout
и записывается в stderr
с помощью pipes
API.
Мне нужно Consumer
, у которого есть тип Consumer (Either String String) m r
для печати фрагмента данных (Left
до stderr
, Right
до stdout
) с помощью одного Consumer
.
Код, который я написал (должен быть улучшен)
Эта функция consumeEither
не обладает гибкостью, поэтому я хочу ее улучшить.
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)
Кроме того, было бы полезно предоставить функцию, которая принимает два Consumer
и объединить их в один Consumer
.
Вопрос
Кто-нибудь знает хороший пример или реализацию следующего интерфейса?
merge :: (Monad m) => Consumer a m r -> Consumer b m r -> Consumer (Either a b) m r
- 1-й аргумент как
stderr
- 2-й аргумент как
stdout
Использование функции
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
Спасибо
Ответы
Ответ 1
(Это ответ @Michael, но я хотел бы написать его здесь, чтобы мы могли перенести вопрос из оставшейся без очереди очереди для тега Haskell.)
См. (+++)
в pipes-extras. Имейте в виду, что Consumer
- это Pipe
(в никуда), поэтому P.toHandle IO.stderr +++ P.stdoutLn :: MonadIO m => Pipe (Either String String) (Either b d) m ()
.
Чтобы получить Consumer
, вам нужно будет избавиться от Lefts
например, с помощью >-> P.concat
или >-> P.drain
. Есть более надежные и красивые способы сделать это с помощью Fold
s.