How can I have a handset with several types of communication?

Let's say I have this code:

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 

Currently, the client always sends an Int and receives a Bool . However, I want the client to also be able to request the highest value that the server has seen so far. So I also need message passing () and getting Int . I could code this as a client sending Either Int () and getting Either Bool Int . However, I would like to make sure that the two do not mix - sending Int always gets a Bool response.

How can I do that?

+6
source share
2 answers

At any time, when you want the pipeline to have two separate interfaces, you need to put the Proxy monad transformer inside yourself. That means you want a type:

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

Given the following two clients for each interface:

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

You would connect them to two server interfaces using:

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

To learn more about this trick, read the Branching, zips, and merges section of the current tutorial.

You can also do it the other way around. You can have Client with two separate interfaces and connect two different Server s. This can improve or improve your problem.

Note that this will be much simpler in pipes-4.0.0 (currently on Github), where types will be much more compressed and you won't need 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 mr client2 :: (Monad m) => () -> Client () Int mr 
+5
source

What you can do is use two pipelines adapted to your two use cases. One server will return Bool , the other will return Int . One client accepts Bool , another accepts Int . In fact, both customers will be Pipe s. One will return a Left Int , the other will return a Right Bool (or vice versa). Two servers can be transferred to IORef or something like that. Then you can use this to track the maximum value. A Pipe , accepting an Either Int Bool at the end of two clients, can be used to do anything with Left and Right cases returned by clients.

+1
source

Source: https://habr.com/ru/post/947709/


All Articles