コンジットとパイプの違いを理解しようとしています。パイプとは異なり、コンジットには残り物の概念があります。残り物は何に役立ちますか?残り物が不可欠な例をいくつか見てみたいと思います。
そして、パイプには残り物の概念がないので、それらと同様の動作を実現する方法はありますか?
コンジットとパイプの違いを理解しようとしています。パイプとは異なり、コンジットには残り物の概念があります。残り物は何に役立ちますか?残り物が不可欠な例をいくつか見てみたいと思います。
そして、パイプには残り物の概念がないので、それらと同様の動作を実現する方法はありますか?
残り物は常に構文解析の一部であるというガブリエラの指摘は興味深いものです。同意するかどうかはわかりませんが、それは構文解析の定義に依存する可能性があります。
残り物を必要とするユースケースには大きなカテゴリがあります。構文解析は確かに1つです。構文解析に何らかの先読みが必要な場合は常に、残り物が必要になります。この一例は、マークダウンパッケージのgetIndented関数にあります。この関数は、特定のインデントレベルで次のすべての行を分離し、残りの行を後で処理できるようにします。
しかし、はるかにありふれた一連の例がコンジット自体に存在します。パックされたデータ(ByteStringやTextなど)を処理するときはいつでも、チャンクを読み取り、それを何らかの方法で分析し、残りを使用して余分なデータをプッシュバックしてから、元のコンテンツで何かを行う必要があります。おそらく、これの最も簡単な例はdropWhileです。
実際、私は残り物をストリーミングライブラリのコアで基本的な機能であると考えているため、コンジット用の新しい1.0インターフェイスでは、残り物を無効にするオプションをユーザーに公開することすらできません。何らかの形でそれを必要としない実際のユースケースはほとんどありません。
答えますpipes
。あなたの質問に対する簡単な答えは、今後のpipes-parse
ライブラリは、より一般的な解析フレームワークの一部として残り物をサポートするということです。人々が残り物を欲しがっているほとんどすべての場合、彼らは実際にパーサーを欲していることがわかります。それが、私が残り物の問題を構文解析のサブセットとして組み立てる理由です。ライブラリの現在のドラフトはここにあります。
ただし、それがどのように機能するかを理解したい場合、pipes-parse
残り物を実装する最も簡単な方法はStateP
、プッシュバックバッファーを格納するために使用することです。これには、次の2つの関数を定義するだけで済みます。
import Control.Proxy
import Control.Proxy.Trans.State
draw :: (Monad m, Proxy p) => StateP [a] p () a b' b m a
draw = do
s <- get
case s of
[] -> request ()
a:as -> do
put as
return a
unDraw :: (Monad m, Proxy p) => a -> StateP [a] p () a b' b m ()
unDraw a = do
as <- get
put (a:as)
draw
最初にプッシュバックバッファを調べて、格納されている要素があるかどうかを確認し、利用可能な場合は1つの要素をスタックからポップします。バッファが空の場合、代わりにアップストリームから新しい要素を要求します。もちろん、何もプッシュバックできない場合はバッファーを使用しても意味がないunDraw
ため、後で保存するために要素をスタックにプッシュすることも定義します。
編集:おっと、残り物が役立つときの便利な例を含めるのを忘れました。マイケルが言うように、takeWhile
そしてdropWhile
残り物の有用なケースです。これがdrawWhile
関数です(Michaelが呼ぶものに類似していますtakeWhile
):
drawWhile :: (Monad m, Proxy p) => (a -> Bool) -> StateP [a] p () a b' b m [a]
drawWhile pred = go
where
go = do
a <- draw
if pred a
then do
as <- go
return (a:as)
else do
unDraw a
return []
ここで、プロデューサーが次のようになっていると想像してください。
producer () = do
respond 1
respond 3
respond 4
respond 6
...そしてあなたはそれを使用した消費者に接続しました:
consumer () = do
evens <- drawWhile odd
odds <- drawWhile even
最初drawWhile odd
の要素が描画した最後の要素をプッシュバックしなかった場合は、を削除しますが、これは2番目のステートメント4
に正しく渡されません` 。drawWhile even