haskell – 如何编写一个向下游发送上游接收列表的管道?

我很难用这个签名写一个管道:

toOneBigList :: (Monad m, Proxy p) => () -> Pipe p a [a] m r

它应该简单地从上游获取所有内容并将它们发送到下游列表中.

我的所有尝试都从根本上被打破了.

任何人都能指出我正确的方向吗?

最佳答案
有两种基于管道的解决方案,我会让你选择你喜欢的解决方案.

注意:目前尚不清楚为什么在下游接口上输出列表而不是直接返回它.

管道式

第一个非常接近基于管道的解决方案使用即将推出的管道,它基本上是完整的,只需要文档.你可以在Github上找到latest draft.

使用pipe-parse,解决方案与Petr提供的管道解决方案完全相同:

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)

draw就像管道一样:它从剩余缓冲区(即StateP部分)请求一个值,如果缓冲区为空则从上游请求一个值.什么都没有表明文件结束.

您可以使用pipes-parse中的wrap函数来包装没有文件结束信号的管道,该函数的类型为:

wrap :: (Monad m, Proxy p) => p a' a b' b m r -> p a' a b' (Maybe b) m s

经典管道风格

第二种选择稍微简单一些.如果要折叠给定的管道,可以使用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

这是对正在发生的事情的更高级别的描述,但它需要传入管道作为显式参数.这取决于你喜欢哪一个.

顺便说一句,这就是为什么我问你为什么要向下游发送一个值.如果您返回折叠列表,上面的内容会简单得多:

foldIt p = execWriterK (liftP . p >-> toListD)

如果p在其代理类型中是完全多态的,则甚至可能不需要liftP.我只是将其作为预防措施.

奖金解决方案

pipe-parse没有提供toOneBigList的原因是它总是一个管道反模式来将结果分组到一个列表中.管道具有几个不错的功能,即使您尝试生成多个列表,也可以永远不必将输入分组到列表中.例如,使用响应组合,您可以让代理生成它将遍历的流的子集,然后注入使用该子集的处理程序:

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

以下是如何使用它的示例:

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

这意味着即使需要对元素进行分组,也不需要将单个元素带入内存.

转载注明原文:haskell – 如何编写一个向下游发送上游接收列表的管道? - 代码日志