[英]Pipes unfolds composition
我目前正在學習管道。 在玩雙向管道時,我注意到展開的構圖看起來非常相似:
(//>) :: Monad m => Proxy x' x b' b m r -> (b -> Proxy x' x c' c m b') -> Proxy x' x c' c m r
-- instead of:
(//>) :: Monad m => Proxy x' x b' b m r -> (b -> Proxy b' b c' c m b') -> Proxy x' x c' c m r
但是我們必須分享x'和x類型,因為我們連接延續的方式:
(>>=) :: Monad m => Proxy a' a b' b m r -> (r -> Proxy a' a b' b m r') -> Proxy a' a b' b m r'
case p0 of
Request x' fx -> Request x' (\x -> go (fx x))
Respond b fb' -> fb b >>= \b' -> (fb' b')
...
但這很容易解決:
import Pipes
import Pipes.Core hiding ((//>))
main :: IO ()
main = runEffect $ lhs //> rhs
infixl 4 //>
(//>) :: Monad m => Proxy x' x b' b m r -> (b -> Proxy b' b c' c m b') -> Proxy x' x c' c m r
p //> f = p >>~ go
where go x = go =<< request =<< f x
lhs :: Proxy x' x String String IO ()
lhs = each [1..10::Int] //> \i -> do
r <- respond $ "response nr. " ++ show i
lift . putStrLn $ "lhs: " ++ show r
rhs :: String -> Proxy String String x x' IO String
rhs x = do
lift . putStrLn $ "rhs 1: " ++ show x
y <- request "yield manually to upstream!"
lift . putStrLn $ "rhs 2: " ++ show y
return "return to upstream"
隨着預期的輸出:
rhs 1: "response nr. 1"
lhs: "yield manually to upstream!"
rhs 2: "response nr. 2"
lhs: "return to upstream"
rhs 1: "response nr. 3"
lhs: "yield manually to upstream!"
rhs 2: "response nr. 4"
lhs: "return to upstream"
rhs 1: "response nr. 5"
lhs: "yield manually to upstream!"
rhs 2: "response nr. 6"
lhs: "return to upstream"
rhs 1: "response nr. 7"
lhs: "yield manually to upstream!"
rhs 2: "response nr. 8"
lhs: "return to upstream"
rhs 1: "response nr. 9"
lhs: "yield manually to upstream!"
rhs 2: "response nr. 10"
lhs: "return to upstream"
我能說的最好也不違反任何法律。
所以最后我的問題是:為什么Pipes使用當前的定義?
我相信(//>)
合同的相關部分是......
(p //> f)
替換每個respond
在p
與f
。
...這意味着f
將以相同的方式處理從p
接收的所有值。 然而,這正是你的組合器所規避的 - 在你的例子中,當你瀏覽each [1..10]
的元素時,你在消息集之間交替。 為了進一步說明這一點,這里是你的代碼的略微修改版本(特別是,我為你的組合器選擇了一個不同的名稱,並在each [1..10]
之后立即使用普通舊(//>)
作為你的組合器在這種情況下表現相同):
infixl 4 //>*
(//>*) :: Monad m =>
Proxy x' x b' b m r -> (b -> Proxy b' b c' c m b') -> Proxy x' x c' c m r
p //>* f = p >>~ go
where go x = f x >>= request >>= go
src :: Monad m => Producer Int m ()
src = each [1..10]
-- The types of lhs and rhs are more restrictive than yours, but for this
-- usage pattern (and with the adjustments I made) that is not a problem.
lhs :: Show a => a -> Server String String IO ()
lhs = \i -> do
r <- respond $ "response nr. " ++ show i
lift . putStrLn $ "lhs: " ++ r
rhs :: String -> Client String String IO String
rhs x = do
lift . putStrLn $ "rhs 0: Will this happen for every value?"
lift . putStrLn $ "rhs 1: " ++ x
y <- request "yield manually to upstream!"
lift . putStrLn $ "rhs 2: " ++ y
return "return to upstream"
我在rhs
開始時滑入的問題的答案......
GHCi> runEffect $ (src //> lhs) //>* rhs
rhs 0: Will this happen for every value?
rhs 1: response nr. 1
lhs: yield manually to upstream!
rhs 2: response nr. 2
lhs: return to upstream
rhs 0: Will this happen for every value?
rhs 1: response nr. 3
lhs: yield manually to upstream!
rhs 2: response nr. 4
lhs: return to upstream
rhs 0: Will this happen for every value?
rhs 1: response nr. 5
lhs: yield manually to upstream!
rhs 2: response nr. 6
lhs: return to upstream
rhs 0: Will this happen for every value?
rhs 1: response nr. 7
lhs: yield manually to upstream!
rhs 2: response nr. 8
lhs: return to upstream
rhs 0: Will this happen for every value?
rhs 1: response nr. 9
lhs: yield manually to upstream!
rhs 2: response nr. 10
lhs: return to upstream
... 沒有。 與使用(//>)
作為最外面的組合器連接函數時發生的情況形成對比,如下所示:
GHCi> runEffect $ src //> (\x -> lhs x //>* rhs)
rhs 0: Will this happen for every value?
rhs 1: response nr. 1
lhs: yield manually to upstream!
rhs 0: Will this happen for every value?
rhs 1: response nr. 2
lhs: yield manually to upstream!
rhs 0: Will this happen for every value?
rhs 1: response nr. 3
lhs: yield manually to upstream!
rhs 0: Will this happen for every value?
rhs 1: response nr. 4
lhs: yield manually to upstream!
rhs 0: Will this happen for every value?
rhs 1: response nr. 5
lhs: yield manually to upstream!
rhs 0: Will this happen for every value?
rhs 1: response nr. 6
lhs: yield manually to upstream!
rhs 0: Will this happen for every value?
rhs 1: response nr. 7
lhs: yield manually to upstream!
rhs 0: Will this happen for every value?
rhs 1: response nr. 8
lhs: yield manually to upstream!
rhs 0: Will this happen for every value?
rhs 1: response nr. 9
lhs: yield manually to upstream!
rhs 0: Will this happen for every value?
rhs 1: response nr. 10
lhs: yield manually to upstream!
這里的每個值都會產生一個單響應服務器,而不是設置最多會給出十個響應的服務器( src //> lhs
),其響應由rhs
客戶端處理。 鑒於沒有第二個響應可以從服務器中獲取, request
之后的rhs
的代碼永遠不會運行。 結果,來自src
的值被統一處理。 為了進一步強調這一點,請注意使用組合器來實現這一點是不必要的: src //> (lhs >~> void . rhs)
做同樣的事情。
(需要注意的另一點是,如果我們將lhs
和rhs
的類型改為最初的那些,我們可以將上面的管道編寫為src //>* (\\x -> lhs x //>* rhs)
。但是,這與(src //>* lhs) //>* rhs
。這是一個關聯性失敗,所以你的組合子不會產生類別。)
它還有助於澄清用(>>~)
替換你的組合器的事情(我確定你已經在測試中嘗試過了):
GHCi> runEffect $ (src //> lhs) >>~ void . rhs
rhs 0: Will this happen for every value?
rhs 1: response nr. 1
lhs: yield manually to upstream!
rhs 2: response nr. 2
src //> lhs
提供多達十個回復; 但是, rhs
只發出兩個請求,因此其他八個響應都沒有被使用。 對我來說,這表明你的組合器最好被表達為一種讓客戶無限期地繼續請求的方式:
-- requestForever :: Monad m => (b -> Client b' b m b') -> b -> Client b' b m r
requestForever :: Monad m =>
(b -> Proxy b' b c' c m b') -> b -> Proxy b' b c' c m r
requestForever f = go
where go x = f x >>= request >>= go
GHCi> runEffect $ (src //> lhs) >>~ requestForever rhs
rhs 0: Will this happen for every value?
rhs 1: response nr. 1
lhs: yield manually to upstream!
rhs 2: response nr. 2
lhs: return to upstream
rhs 0: Will this happen for every value?
rhs 1: response nr. 3
lhs: yield manually to upstream!
rhs 2: response nr. 4
lhs: return to upstream
rhs 0: Will this happen for every value?
rhs 1: response nr. 5
lhs: yield manually to upstream!
rhs 2: response nr. 6
lhs: return to upstream
rhs 0: Will this happen for every value?
rhs 1: response nr. 7
lhs: yield manually to upstream!
rhs 2: response nr. 8
lhs: return to upstream
rhs 0: Will this happen for every value?
rhs 1: response nr. 9
lhs: yield manually to upstream!
rhs 2: response nr. 10
lhs: return to upstream
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.