9

私は簡単な仕事をしています - ファイルからたくさんの行を読み込んで、それらのそれぞれで何かをします。最初のものを除いて - これは無視されるべきいくつかの見出しです.

そこで、コンジットを試してみようと思いました。

printFile src = runResourceT $ CB.sourceFile src =$= 
    CT.decode CT.utf8 =$= CT.lines =$= CL.mapM_ putStrLn

涼しい。

だから今、最初の行を削除したいだけです...そしてそのための機能があるようです-

printFile src = runResourceT $ CB.sourceFile src =$= 
    CT.decode CT.utf8 =$= CT.lines =$= drop 1 =$= CL.mapM_ putStrLn

うーん - しかし今、私は drop が署名型を持っていることに気付きSink a m ()ました。パイプに Monad インスタンスを使用し、ドロップを使用していくつかの要素を効果的にドロップできると誰かが提案したので、これを試しました:

drop' :: Int -> Pipe a a m ()
drop' n = do
  CL.drop n
  x <- await
  case x of 
    Just v -> yield v
    Nothing -> return ()

パイプのモナドインスタンスは同じタイプのパイプにのみ適用されるため、タイプチェックは行われません-シンクは出力として Void を持っているため、このようには使用できません。

pipes と pipes-core をざっと見てみると、pipes-core には期待どおりの機能があることがわかりました。pipes は最小限のライブラリですが、ドキュメントには実装方法が示されています。

だから私は混乱しています - 私が見逃している重要な概念があるかもしれません..関数を見ました

sequence ::  Sink input m output -> Conduit input m output

しかし、出力値が () であるため、それは正しい考えではないようです。

CL.sequence (CL.drop 1) :: Conduit a m ()    

ストリーミングは本当に必要ないので、おそらく戻ってlazy-ioを使用しますが、それを行う適切な方法を知りたいです。

4

1 に答える 1

6

まず、簡単な答え:

... =$= CT.lines =$= (CL.drop 1 >> CL.mapM_ putStrLn)

より長い説明: 実際には 2 つの異なる方法で実装できますdrop。いずれにせよ、最初nに入力から要素を削除します。次に何をするかについては、2 つの選択肢があります。

  • 終わったと言う
  • 入力ストリームから残りのすべての項目の出力を開始します

前者の動作はSinkが実行するもの (およびdrop実際に行うこと) であり、後者は の動作ですConduit。実際、モナド構成を介して前者から後者を生成できます。

dropConduit n = CL.drop n >> CL.map id

その後dropConduit、最初に説明したように使用できます。これは、モナド構成と融合の違いを示す良い方法です。前者は 2 つの関数が同じ入力ストリームで動作できるようにし、後者は一方の関数がもう一方の関数にストリームをフィードできるようにします。

私はベンチマークを行っていませんが、モナド構成がもう少し効率的であることはかなり確信しています。

于 2012-05-31T15:21:19.143 に答える