6

このコードがあるとします:

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。ただし、この 2 つが混在しないようにしたいと思います。 を送信すると、Int常にBool応答が返されます。

これはどのように行うことができますか?

4

2 に答える 2

5

パイプラインに 2 つの別個のインターフェースを持たせたいときはいつでも、Proxyモナド変換子をそれ自体の中に入れ子にする必要があります。つまり、次のタイプが必要です。

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

各インターフェイスに次の 2 つのクライアントがあるとします。

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

以下を使用して、それらを 2 つのサーバー インターフェイスに接続します。

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

main = runProxy (client1 >-> oneInterface)

このトリックの詳細については、現在のチュートリアルの分岐、zip、およびマージのセクションをお読みください。

また、その逆もできます。Clientを 2 つの別個のインターフェイスで使用して、2 つの異なる を接続できますServer。これは、問題に適している場合とそうでない場合があります。

これは (現在 Github で) でより簡単になることに注意してくださいpipes-4.0.0。型はより簡潔になり、次の必要はありません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
于 2013-06-20T15:59:41.847 に答える