2017-06-08 77 views
0

我正在嘗試使用管道來模擬雙向實例最理想的問題。基本上,我有類似如下結構:如何正確使用雙向管道?

api logic 
    | ^
    | | 
    v | 
    A A' 
layer 1 
    B B' 
    | ^
    | | 
    v | 
layer 2  

所以基本上,我有layer 1這是一個雙向的變壓器。該模型是基於拉的,所以我通過logic組件的拉來觸發消息流轉換。

所以我應該有layer1 :: Proxy A' A B' B m x的想法是,從​​拉apiA,做一些改造A -> B然後使用從二層的B',適用B' -> A'並把它傳遞給logic

什麼是不明確的是:我知道如何requestA和迴應B但我怎麼產生從B'A'?似乎沒有在適合在這裏庫中的任何組合子...

回答

2

有三種類型,你需要注意的:Client S可request但從來沒有respondServer S可respond但從來沒有requestProxy可以做都。

request/respond的參數是要發送的值,並且您綁定的結果分別是響應/請求。這對於request(你綁定響應)來說很直觀,但是我花了一點時間才點擊了respond(你需要綁定下一個請求)。它使你的處理步驟整潔的小遞歸函數。 (我最初的直覺是使用Control.Monad.forever,這對於單向管道很好,但在這裏是錯誤的工具。)

這個問題讓人感到困惑:因爲管道本身是同步的,所以你需要獲得一個初始值來傳遞和把事情踢開。您可以將它傳遞到request(製作一個拉管道,您與(>~>)組成),或者將其傳遞到respond(製作一個推管道,您與(>+>)組成)。然後你將初始值傳遞給組合管道,給你Effect m r可以去runEffect

我在下面的例子中使用了拉管道,因爲它符合你的API請求隱喻。它實現了這三個階段的雙向管道:

+--------+ Yoken +-----------+ Token +--------+ 
|  |<-------|   |<-------|  | 
| server |  | transform |  | client | 
|  |------->|   |------->|  | 
+--------+ String +-----------+ String +--------+ 
           (shouty) 

client生成請求Token S和打印出的反應。 transformToken s變成Yoken s(嘿,鍵是彼此相鄰)並將它們傳遞給上游。它還通過提供和追加!將響應轉化爲喊聲。 server收到Yoken s並生成請求的號碼yo s。

import Data.Char 
import Control.Monad 
import Control.Monad.IO.Class 
import Pipes.Core 
import System.IO 

data Token = Token Int 
data Yoken = Yoken Int 

main :: IO() 
main = do 
    hSetBuffering stdout NoBuffering 
    -- We have to get an initial n outside the pipeline to kick things off. 
    putStr "N? " 
    n <- read <$> getLine 
    runEffect $ server >+> transform >+> client $ Token n 

-- The "server" generates a string of "yo"s based on the number inside the Yoken 
server :: Monad m => Yoken -> Server Yoken String m a 
server (Yoken n) = (respond . concat $ replicate n "yo") >>= server 

-- A processing step just for the sake of having one, turn the Token into a 
-- Yoken, upcase the string, and append a "!". 
transform :: Monad m => Token -> Proxy Yoken String Token String m a 
transform (Token t) = do 
    resp <- request $ Yoken t 
    next <- respond $ map toUpper resp ++ "!" 
    transform next 

-- Clients request "yo"s, by sending `Token`s upstream. 
client :: Token -> Client Token String IO a 
client t = do 
    resp <- request t 
    n <- liftIO $ putStrLn resp *> putStr "N? " *> fmap read getLine 
    client $ Token n 
+0

非常感謝您的關心,回答我孤獨的問題!我設法自己找到答案感謝http://hackage.haskell.org/package/pipes-2.3.0/docs/Control-Proxy-Tutorial.html – insitu