是否可能创建一个函数,以便可以从pipes内部向外构建Proxy
?所谓内部向外,是指通过连接上游和下游连接的函数创建代理。最理想的(但不可能的)签名是:
makeProxy :: (Monad m) =>
(Server a' a m r -> Client b' b m r -> Effect m r) ->
Proxy a' a b' b m r
我们遇到的第一个问题是构建代理的机械问题。除非我们将
Server
和Client
都设置为M
,否则我们无法知道函数是否查看了哪个。即使这样做,我们也只能知道它查看了哪一个,而不知道它试图向上游或下游发送什么值。如果我们关注上游端,唯一知道的是某些东西试图找出上游代理是什么,因此我们需要决定始终导致更远的上游Request
或Respond
。无论我们如何回答,我们只能提供()
。这意味着我们可以向上游生产者发出Request ()
或立即Respond ()
。如果我们考虑为两端都做出这个选择,那么只有四个可能的函数。以下函数根据它们的上游和下游连接是否将有趣的数据发送到下游(D
)或上游(U
)而命名。betweenDD :: (Monad m) =>
(Server () a m r -> Client () b m r -> Effect m r) ->
Proxy () a () b m r
betweenDD = undefined
betweenDU :: (Monad m) =>
(Server () a m r -> Client b' () m r -> Effect m r) ->
Proxy () a b' () m r
betweenDU = undefined
betweenUU :: (Monad m) =>
(Server a' () m r -> Client b' () m r -> Effect m r) ->
Proxy a' () b' () m r
betweenUU f = reflect (betweenDD g)
where g source sink = f (reflect sink) (reflect source)
betweenUD :: (Monad m) =>
(Server a' () m r -> Client () b m r -> Effect m r) ->
Proxy a' () () b m r
betweenUD = undefined
betweenDD
是最有趣的函数之一,它可以在一个Producer
和一个Consumer
之间建立一个管道;betweenUU
可以为运行上游的管道执行相同的操作。 betweenDU
会从两个源中请求数据并消费它。 betweenUD
将生成数据并将其发送到两个目标之一。
我们能否为betweenDD
提供定义?如果不能,我们是否可以为以下更简单的函数提供定义?
belowD :: (Monad m) =>
(Producer a m r -> Producer b m r) ->
Proxy () a () b m r
aboveD :: (Monad m) =>
(Consumer b m r -> Consumer a m r) ->
Proxy () a () b m r
这个问题的动机是想要编写
belowD
,以用于回答关于P.zipWith
的问题。
示例
这个示例实际上基本上是启发这个问题的问题。
假设我们想要创建一个Pipe
,用于给通过它的值进行编号。 Pipe
将具有从上游传下来的值a
和从下游传出的值(n,a)
;换句话说,它将是一个Pipe a (n, a)
。
我们将通过与数字进行zip
解决此问题。 与数字进行zip
的结果是一个从Producer a
到Producer (n, a)
的函数(->)
。
import qualified Pipes.Prelude as P
number' :: (Monad m, Num n, Enum n) => Producer a m () -> Producer (n, a) m ()
number' = P.zip (fromList [1..])
尽管
Pipe
会从上游消费 a
,但从函数的角度来看,它需要一个 a
的 Producer
来提供这些值。如果我们有 belowD
的定义,我们可以写成:number :: (Monad m, Num n, Enum n) => Pipe a (n, a) m ()
number = belowD (P.zip (fromList [1..]))
给出一个适当的 fromList
定义
fromList :: (Monad m) => [a] -> Producer a m ()
fromList [] = return ()
fromList (x:xs) = do
yield x
fromList xs
betweenDU
情况,其中所有有趣的数据都在流动。betweenDU f = makeProxy g where g fa' fb = f (fa' ()) (fb ())
- CirdecmakeProxy
的原始签名,因为Server
和Client
都缺少一个参数。在组合的Proxy
管道中,除了(最多)一个之外的每个Proxy
都必须带有一个参数(类型强制执行此操作)。你的Server
和Client
都没有参数,这意味着它们通常是不可能连接的。 - Gabriella Gonzalez