3

pipes-csv ライブラリを使用して csv ファイルを読み込んでいます。最初の行を読んで、あとで続きを読みたい。残念ながら、 Pipes.Prelude.head 関数が戻った後。パイプは何とか閉じられています。最初に csv の先頭を読み取り、残りを後で読み取る方法はありますか。

import qualified Data.Vector as V
import Pipes
import qualified Pipes.Prelude as P
import qualified System.IO as IO
import qualified Pipes.ByteString as PB
import qualified Data.Text as Text
import qualified Pipes.Csv as PCsv
import Control.Monad (forever)

showPipe :: Proxy () (Either String (V.Vector Text.Text)) () String IO b
showPipe = forever $ do
    x::(Either String (V.Vector Text.Text)) <- await
    yield $ show x


main :: IO ()
main = do
  IO.withFile "./test.csv"
              IO.ReadMode
              (\handle -> do
                  let producer = (PCsv.decode PCsv.NoHeader (PB.fromHandle handle))
                  headers <- P.head producer
                  putStrLn "Header"
                  putStrLn $ show headers
                  putStrLn $ "Rows"
                  runEffect ( producer>->
                              (showPipe) >->
                              P.stdoutLn)
               )

最初にヘッダーを読み取らなければ、csv 全体を問題なく読み取ることができます。

main :: IO ()
main = do
  IO.withFile "./test.csv"
              IO.ReadMode
              (\handle -> do
                  let producer = (PCsv.decode PCsv.NoHeader (PB.fromHandle handle))
                  putStrLn $ "Rows"
                  runEffect ( producer>->
                              (showPipe) >->
                              P.stdoutLn)
               )
4

1 に答える 1

2

Pipes.CsvPipes.awaitヘッダーを処理するための資料がありますが、この質問はor elseのより洗練された使用法を実際に探していると思いますPipes.next。最初next

>>> :t Pipes.next 
Pipes.next :: Monad m => Producer a m r -> m (Either r (a, Producer a m r))

nextプロデューサーを検査する基本的な方法です。リストのパターン マッチングのようなものです。リストでは、2 つの可能性は[]x:xs- ここではLeft ()Right (headers, rows)です。後者のペアは、探しているものです。もちろん、IOそれを手に入れるにはアクション (ここでは ) が必要です。

main :: IO ()
main = do
  handle <- IO.openFile  "./test.csv" IO.ReadMode
  let producer :: Producer (V.Vector Text.Text) IO ()
      producer = PCsv.decode PCsv.NoHeader (PB.fromHandle handle)  >-> P.concat
  e <- next producer
  case e of
    Left () -> putStrLn "No lines!"
    Right (headers, rows) -> do
      putStrLn "Header"
      print headers
      putStrLn $ "Rows"
      runEffect ( rows >-> P.print)
  IO.hClose handle

ここでは値が邪魔になるので、値 (解析しない行) を次のようEitherに削除します。LeftP.concat

nextはパイプライン内では動作しませんがProducer、最後に最終的な戻り値を持つ一種の「有効なリスト」として扱います。上記の特定の効果は、もちろんawait、パイプライン内で動作する で実現できます。これを使用して、パイプラインで発生する最初のアイテムをインターセプトし、それに基づいて IO を実行してから、残りの要素を転送できます。

main :: IO ()
main = do
  handle <- IO.openFile  "./grades.csv" IO.ReadMode
  let producer :: Producer (V.Vector Text.Text) IO ()
      producer = PCsv.decode PCsv.NoHeader (PB.fromHandle handle)  >-> P.concat
      handleHeader :: Pipe (V.Vector Text.Text) (V.Vector Text.Text) IO ()
      handleHeader = do
        headers <- await  -- intercept first value
        liftIO $ do       -- use it for IO
          putStrLn "Header"
          print headers
          putStrLn $ "Rows"
        cat               -- pass along all later values
  runEffect (producer >-> handleHeader >-> P.print)
  IO.hClose handle

違いは、前のプログラムで行ったように、ifproducerが空の場合、これを宣言できないことだけです。No lines!

、または単にとしてshowPipe定義できることに注意してください(ただし、追加する特殊なタイプを使用します)。P.map showP.show

于 2016-12-20T19:34:50.910 に答える