takeWhileとの間のクロスのようなコンジットを作成しようとしていisolateます。つまり、述語が保持されなくなるか、バイト制限に達するまで、入力から消費し、出力に譲ります。型シグネチャが
isolateWhile :: (Monad m) => Int -> (Word8 -> Bool) -> Conduit ByteString m ByteString
その使用例として:
{-# LANGUAGE OverloadedStrings #-}
import Data.Conduit
import qualified Data.Conduit.List as CL
import qualified Data.Conduit.Binary as CB
import Control.Monad.Trans.Class
charToWord = fromIntegral . fromEnum
example :: Int -> Char -> IO ()
example limit upTo = do
untaken <- CB.sourceLbs "Hello, world!" $= conduit $$ CB.sinkLbs
putStrLn $ "Left " ++ show untaken
where
conduit = do
taken <- toConsumer $ isolateWhile limit (/= charToWord upTo) =$ CB.sinkLbs
lift $ putStrLn $ "Took " ++ show taken
CL.map id -- pass the rest through untouched
私はそれを期待しています
ghci> example 5 'l'
Took "He"
Left "llo, world!"
ghci> example 5 'w'
Took "Hello"
Left ", world!"
ただし、 の最も単純な定義は次のisolateWhileとおりです。
isolateWhile limit pred = CB.isolate limit =$= CB.takeWhile pred
収量
ghci> example 5 'l'
Took "He"
Left ", world!"
ghci> example 5 'w'
Took "Hello"
Left ", world!"
つまり、はを残して破棄し、をisolateすべて使い果たします。このデータ損失は、アプリケーションにとって望ましくありません。ただし、2 番目のケースが期待どおりの結果をもたらすことは注目に値します。HelloHetakeWhilello
=$=そのようなオペランドを交換すると:
isolateWhile limit pred = CB.takeWhile pred =$= CB.isolate limit
それで
ghci> example 5 'l'
Took "He"
Left ", world!"
ghci> example 5 'w'
Took "Hello"
Left ""
これで、最初のテストは修正されましたが、2 番目のテストは壊れました。今回は、takeWhile必要なものは何でもisolate取り、そのサブセットを取ります。しかし、takeWhile使用しisolateないものは破棄され、これは望ましくありません。
最後に、私は試しました:
isolateWhile limit pred = do
untaken <- CB.isolate limit =$= (CB.takeWhile pred >> CL.consume)
mapM_ leftover $ reverse untaken
これは実際に機能します!受け入れるものisolateと受け入れtakeWhileないものはすべて によって消費されCL.consume、 でストリームに戻されますleftover。残念ながら、これは恐ろしいクラッジのように思えlimitますleftover. それは無駄のようです。
私が考えることができる唯一の解決策は、プリミティブの観点からawaitそれyieldを書くleftoverことです。これにより、多くの問題を無駄にすることなくすべての問題が解決されますが、もっと良い方法があるはずです。takeWhileisolate
私は何かを見逃していますか、それともこれを書くより良い方法は本当にありませんか?