Pet*_*lák 14 haskell conduit haskell-pipes
我试图了解导管和管道之间的差异.与管道不同,管道具有剩余物的概念.什么是剩菜有用?我想看一些剩菜必不可少的例子.
由于管道没有剩余的概念,有没有办法与它们实现类似的行为?
Mic*_*man 17
加布里埃尔的观点是残羹剩饭总是解析的一部分很有意思.我不确定我会同意,但这可能只取决于解析的定义.
有一大类用例需要剩菜.解析肯定是一个:任何时候解析都需要某种前瞻,你需要剩下的东西.其中一个例子是markdown包的getIndented函数,该函数将所有即将到来的行隔离一定的缩进级别,剩下的行将在稍后处理.
但是更多平凡的例子存在于管道本身.无论何时处理打包数据(如ByteString或Text),您都需要读取一个块,以某种方式分析它,使用剩余的来推回额外的数据,然后对原始内容执行某些操作.也许最简单的例子就是dropWhile.
实际上,我认为剩下的是流媒体库的核心基本功能,管道的新1.0接口甚至不会向禁用剩余的用户公开选项.我知道很少有真实世界的用例不需要这种或那种方式.
Gab*_*lez 16
我会回答pipes.对你的问题的简短回答是即将推出的pipes-parse库将支持剩余部分作为更通用的解析框架的一部分.我发现几乎每个人都想要剩菜的情况下他们实际上都想要一个解析器,这就是为什么我将剩余问题作为解析的一个子集.您可以在此处找到库的当前草稿.
但是,如果您想了解如何pipes-parse使其工作,实现剩余部分的最简单方法是仅用于StateP存储回送缓冲区.这只需要定义以下两个函数:
import Control.Proxy
import Control.Proxy.Trans.State
draw :: (Monad m, Proxy p) => StateP [a] p () a b' b m a
draw = do
s <- get
case s of
[] -> request ()
a:as -> do
put as
return a
unDraw :: (Monad m, Proxy p) => a -> StateP [a] p () a b' b m ()
unDraw a = do
as <- get
put (a:as)
Run Code Online (Sandbox Code Playgroud)
draw首先查阅pushback缓冲区以查看是否存在任何存储的元素,如果可用,则从堆栈中弹出一个元素.如果缓冲区为空,则它从上游请求新元素.当然,如果我们不能将任何东西推回去,那么就没有缓冲区,所以我们还定义unDraw了将一个元素推送到堆栈以便以后保存.
编辑:哎呀,我忘了提供剩余时间有用的有用例子.就像迈克尔所说,takeWhile并且dropWhile是残羹剩饭的有用案例.这是drawWhile函数(类似于Michael所说的takeWhile):
drawWhile :: (Monad m, Proxy p) => (a -> Bool) -> StateP [a] p () a b' b m [a]
drawWhile pred = go
where
go = do
a <- draw
if pred a
then do
as <- go
return (a:as)
else do
unDraw a
return []
Run Code Online (Sandbox Code Playgroud)
现在假设您的制作人是:
producer () = do
respond 1
respond 3
respond 4
respond 6
Run Code Online (Sandbox Code Playgroud)
...而且你把它连接到使用的消费者:
consumer () = do
evens <- drawWhile odd
odds <- drawWhile even
Run Code Online (Sandbox Code Playgroud)
如果第一个drawWhile odd没有推回它绘制的最后一个元素,那么你将丢弃4,这将无法正确传递到第二个drawWhile even语句`.