當前使用conduit
更容易實現的一個經典示例是處理來自上游的輸入結束。例如,如果要摺疊值列表並在管道中綁定結果,則無法在pipes
內完成此操作,而無需在pipes
之上設計額外的協議。
實際上,這正是即將到來的pipes-parse
庫解決的問題。它在pipes
之上設計了一個Maybe
協議,然後定義了方便的功能,用於從上游繪製關於該協議的輸入。
例如,你有onlyK
函數,該函數的管幷包裝在Just
所有輸出,然後結束與Nothing
:
onlyK :: (Monad m, Proxy p) => (q -> p a' a b' b m r) -> (q -> p a' a b' (Maybe b) m r)
還具有justK
功能,其定義從管函子這是Maybe
-unaware到是Maybe
知曉的向後兼容性
justK :: (Monad m, ListT p) => (q -> p x a x b m r) -> (q -> p x (Maybe a) x (Maybe b) m r)
justK idT = idT
justK (p1 >-> p2) = justK p1 >-> justK p2
,然後一旦你有一個管道尊重該協議,您可以使用大量的解析器,通過Nothing
檢查爲您抽象。最簡單的一個是draw
:
draw :: (Monad m, Proxy p) => Consumer (ParseP a p) (Maybe a) m a
它檢索a
類型的值或在ParseP
代理變壓器失敗如果上游跑出輸入的。你也可以一次取多個值:
drawN :: (Monad m, Proxy p) => Int -> Consumer (ParseP a p) (Maybe a) m [a]
drawN n = replicateM n draw -- except the actual implementation is faster
...和其他幾個很好的功能。用戶從來不必直接與輸入信號的末端進行交互。
通常當人們要求輸入結束處理時,他們真正想要的是解析,這就是爲什麼pipes-parse
將輸入結束問題作爲解析子集的原因。
我很好奇,這個協議如何與管道可組合性一起去?假設我有一個讀取文件的管道'readFileK',併發送'Nothing'來表示結束。如果我做'(readFileK「file1」>> readFileK「file2」)> - > otherPipeK'那麼'otherPipeK'會收到'Nothing'兩次?另一方面,如果我有'readFileK'文件'>> - >(pipe1K >> pipe2K),並且當'pipe1K'正在處理時文件的輸入被耗盡,那麼'pipe2K'永遠不會知道輸入已經被耗盡。 – 2013-03-07 20:01:39
這就是爲什麼'onlyK'是一個單獨的組合器,而'Nothing'行爲沒有內置到源中。這樣你就可以將多個源合併爲一個,比如'onlyK(readFileS「file」> => readSocketS socket)''。你的第二個例子不會導致任何問題。如果'pipe1K'輸入完了,它將在'ParseP'中失敗,'pipe2K'永遠不會運行。沒有一個解析原語能夠越過輸入標記的末尾。 – 2013-03-07 20:58:59