A pipe like signalExhausted
can't be defined, but a function equivalent to (>-> signalExhausted)
can.
>->
pull
カテゴリの特殊バージョンです。実行は、上流のプロキシからデータをプルする下流のプロキシによって駆動されます。ダウンストリーム プロキシは空のリクエストを()
アップストリームに送信し、値を保持するレスポンスがアップストリーム プロキシから返されるまでブロックします。アップストリーム プロキシが使い果たされ、送り返す値がなくなると、return
s. return
の定義で、これらの例にとって重要なことがわかりますeach
。
each = F.foldr (\a p -> yield a >> p) (return ())
-- what to do when the data's exhausted ^
ダウンストリーム プロキシは実行を継続するために値を必要としますが、パイプ ライブラリが提供できる可能性のある値がないため、ダウンストリーム プロキシは二度と実行されません。二度と実行されないため、データを変更したり、データに反応したりすることはできません。
この問題には 2 つの解決策があります。最も簡単な方法は、上流のパイプに渡して、完了後に a を追加することです。map
Value
yield Exhausted
import Pipes
import qualified Pipes.Prelude as P
data Value a = Value a | Exhausted
deriving (Show)
signalExhausted p = p >-> P.map Value >> yield Exhausted
signalExhausted
これは、関数が の代わりになることを除いて、まさにあなたが探していることを行います(>-> signalExhausted)
。
let xs = words "hubble bubble toil and trouble"
print . P.toList . signalExhausted $ each xs
[Value "hubble",Value "bubble",Value "toil",Value "and",Value "trouble",Exhausted]
この問題に対するより一般的な解決策は、アップストリーム プロキシが戻るのを停止し、代わりに使い果たされたときにダウンストリームに信号を送ることです。関連する質問への回答で、その方法を示しました。
import Control.Monad
import Pipes.Core
returnDownstream :: Monad m => Proxy a' a b' b m r -> Proxy a' a b' (Either r b) m r'
returnDownstream = (forever . respond . Left =<<) . (respond . Right <\\)
これは、 eachrespond
をrespond . Right
および に置き換え、応答return
とともにforever . respond . left
リターンを下流に送信します。
returnDownstream
探しているものよりも一般的です。それを使用して を再作成する方法を示すことができますsignalExhausted
。returnDownstream
戻るパイプを決して戻らないパイプに変換し、代わりにその戻り値Left
を an の値として下流に転送しEither
ます。
signalExhausted p = returnDownstream p >-> respondLeftOnce
respondLeftOnce
ダウンストリーム プロキシの例です。ダウンストリーム プロキシは、 に保持されている通常の値と に保持されRight
ている戻り値を識別できますLeft
。
respondLeftOnce :: Monad m => Pipe (Either e a) (Value a) m ()
respondLeftOnce = go
where
go = do
ea <- await
case ea of
Right a -> yield (Value a) >> go
Left _ -> yield Exhausted -- The upstream proxy is exhausted; do something else