如何拥有多种通信类型的管道?

时间:2013-06-20 07:21:47

标签: haskell haskell-pipes

说我有这段代码:

import Control.Monad.State hiding (StateT)
import Control.Proxy

server :: (Proxy p, Monad m) => Int -> Server p Int Bool (StateT Int m) ()
server = runIdentityK loop
    where loop arg = do
        currMax <- lift get
        lift $ put $ max currMax arg
        nextArg <- respond (even arg)
        loop nextArg

client :: (Proxy p, Monad m) => Client p Int Bool m ()
client = runIdentityP loop
    where loop = go 1
          go i = do
            isEven <- request i
            go $ if isEven
                then i `div` 2
                else i * 3 + 1

目前,客户端始终发送Int,并收到Bool。但是,我希望客户端也能够查询到目前为止服务器已经看到的最高值。所以我还需要发送()和接收Int的通信。我可以将其编码为发送Either Int ()并接收Either Bool Int的客户端。但是,我想确保两者不是混合的 - 发送Int始终会得到Bool响应。

如何做到这一点?

2 个答案:

答案 0 :(得分:5)

每当您希望管道具有两个单独的接口时,您必须将Proxy monad变换器嵌套在其自身中。这意味着您需要类型:

twoInterfaces
    :: (Monad m, Proxy p1, Proxy p2 )
    => () -> Int -> Server p1 Int Bool (Server p2 () Int m) r
twoInterfaces () n = runIdentityP . hoist runIdentityP $ do
    x <- respond A        -- Use outer interface
    y <- lift $ respond B -- Use inner interface
    ...

为每个接口提供以下两个客户端:

client1 :: (Monad m, Proxy p) => () -> Client p Int Bool m r
client2 :: (Monad m, Proxy p) => () -> Client p ()  Int  m r

您可以使用以下方法将它们连接到两个服务器接口:

oneInterface () = runProxy (twoInterfaces () >-> client1)

main = runProxy (client1 >-> oneInterface)

要了解有关此技巧的更多信息,请阅读当前教程的Branching, zips, and merges部分。

你也可以反过来做。你可以拥有一个带有两个独立界面的Client,并连接两个不同的Server。这可能会或可能不会更好地适合您的问题。

请注意,这会在pipes-4.0.0(目前在Github上)变得更加简单,其中类型将更加简洁,您不会需要runIdentityP

twoInterfaces
    :: (Monad m) => () -> Int -> Server Int Bool (Server () Int m) r
twoInterface () n = do
    x <- respond A
    y <- lift $ respond B
   ...

client1 :: (Monad m) => () -> Client Int Bool m r
client2 :: (Monad m) => () -> Client ()  Int  m r

答案 1 :(得分:1)

您可以使用两个管道,根据您的两个用例量身定制。一台服务器将返回Bool,另一台服务器将返回Int。一个客户接受Bool,另一个接受Int。这两个客户实际上是Pipe。一个会返回Left Int,另一个会返回Right Bool(反之亦然)。这两个服务器可以在IORef或类似的东西中传递。然后,您可以使用它来跟踪最大值。在两个客户端结束时Pipe Either Int Bool可以用来对客户返回的LeftRight个案做一些事情。