Gia*_*sio 4 haskell haskell-pipes
我很难写pipe这个签名:
toOneBigList :: (Monad m, Proxy p) => () -> Pipe p a [a] m r
Run Code Online (Sandbox Code Playgroud)
它应该简单地a从上游获取所有s并将它们发送到下游列表中.
我的所有尝试都从根本上被打破了.
任何人都能指出我正确的方向吗?
有两种pipes解决方案,我会让你选择你喜欢的解决方案.
注意:目前尚不清楚为什么在下游接口上输出列表而不是直接返回它.
第一个,非常接近conduit基于解决方案使用即将到来的pipes-pase,这基本上是完整的,只需要文档.您可以在Github上找到最新的草稿.
使用pipes-parse,解决方案与conduitPetr给出的解决方案相同:
import Control.Proxy
import Control.Proxy.Parse
combine
:: (Monad m, Proxy p)
=> () -> Pipe (StateP [Maybe a] p) (Maybe a) [a] m ()
combine () = loop []
where
loop as = do
ma <- draw
case ma of
Nothing -> respond (reverse as)
Just a -> loop (a:as)
Run Code Online (Sandbox Code Playgroud)
draw就像conduit是await:它从剩余缓冲区(即StateP部分)请求一个值,如果缓冲区为空则从上游请求一个值. Nothing表示文件结束.
您可以使用wrap函数from 来包装没有文件结束信号的管道,该函数pipes-parse具有以下类型:
wrap :: (Monad m, Proxy p) => p a' a b' b m r -> p a' a b' (Maybe b) m s
Run Code Online (Sandbox Code Playgroud)
第二种选择稍微简单一些.如果要折叠给定的管道,可以直接使用WriterP:
import Control.Proxy
import Control.Proxy.Trans.Writer
foldIt
:: (Monad m, Proxy p) =>
(() -> Pipe p a b m ()) -> () -> Pipe p a [b] m ()
foldIt p () = runIdentityP $ do
r <- execWriterK (liftP . p >-> toListD >-> unitU) ()
respond r
Run Code Online (Sandbox Code Playgroud)
这是对正在发生的事情的更高级别的描述,但它需要传入管道作为显式参数.这取决于你喜欢哪一个.
顺便说一句,这就是为什么我问你为什么要向下游发送一个值.如果您返回折叠列表,上面的内容会简单得多:
foldIt p = execWriterK (liftP . p >-> toListD)
Run Code Online (Sandbox Code Playgroud)
在liftP可能甚至如果有必要p在其代理类型完全多态性.我只是将其作为预防措施.
原因pipes-parse并不是toOneBigList说它总是一个管道反模式将结果分组到一个列表中. pipes有几个很好的功能,即使你试图产生多个列表,也可以永远不必将输入分组到列表中.例如,使用respond组合,您可以让代理生成它将遍历的流的子集,然后注入使用该子集的处理程序:
example :: (Monad m, Proxy p) => () -> Pipe p a (() -> Pipe p a a m ()) m r
example () = runIdentityP $ forever $ do
respond $ \() -> runIdentityP $ replicateM_ 3 $ request () >>= respond
printIt :: (Proxy p, Show a) => () -> Pipe p a a IO r
printIt () = runIdentityP $ do
lift $ putStrLn "Here we go!"
printD ()
useIt :: (Proxy p, Show a) => () -> Pipe p a a IO r
useIt = example />/ (\p -> (p >-> printIt) ())
Run Code Online (Sandbox Code Playgroud)
以下是如何使用它的示例:
>>> runProxy $ enumFromToS 1 10 >-> useIt
Here we go!
1
2
3
Here we go!
4
5
6
Here we go!
7
8
9
Here we go!
10
Run Code Online (Sandbox Code Playgroud)
这意味着即使需要对元素进行分组,也不需要将单个元素带入内存.