【问题标题】:How to find the end of Pipe如何找到管道的末端
【发布时间】:2014-03-15 15:03:57
【问题描述】:

在下面的代码中我该怎么做

  • 更改 stdoutCharConsumer 以便在打印输入流中的所有数据后打印一个换行符

  • 实现mixinmixin'

不进入 Pipes.Internal?可能吗?我需要类似next Producers 的函数。

我使用 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: 现在,在我阅读了基于拉/推的流之后,我认为即使使用 Pipes.Internal 也是不可能的。是真的吗?

【问题讨论】:

  • 您了解interleave 的工作原理吗?请注意,当管道 p 完成时,next p 返回 Left result
  • 我想我理解它,但它适用于生产者,而不是管道。这就是为什么我将interleave 留在这里作为我为 Producers 拥有并希望为 Pipes 拥有的示例的原因
  • 抱歉,我以为next 有更通用的类型。如果您确实深入了解Pipes.Internal,请查看MonadPlus 实例以获取灵感。可能您可以调整mplus 实现背后的想法,以获得类似于interleave 的更一般的Proxy 值。

标签: haskell haskell-pipes


【解决方案1】:

ConsumersPipes 都不知道上游输入结束。为此,您需要来自pipes-parseParsers。

相比Consumers,Parsers对Producers的认识更直接;他们的draw 函数(大致类似于await)在找到输入结束时返回Nothing

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

要运行解析器,我们调用 evalStateT 而不是 runEffect

P.evalStateT stdoutCharParser (interleave characters digits) 

至于mixinmixin',我怀疑它们将无法按预期工作。原因是结果Pipe 必须知道上游终止,以便知道何时产生作为参数传递的Producer 的剩余值。

【讨论】:

  • 也许你是对的。我会这样解释。管道不决定流是否关闭,而是返回上游控制。当上游生产者决定它已经用尽时,它只是终止而不通知它下面的管道/cousumer。
  • @amakarov 没错。 Parserspipes-parse 将较少的控制权交给Producer。他们可以检测输入结束并将值推回Producer
猜你喜欢
  • 2020-01-25
  • 1970-01-01
  • 2014-11-24
  • 2015-07-12
  • 2018-09-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多