2016-12-20 16 views
2

私はpipes-csvライブラリを使ってcsvファイルを読んでいます。私は最初の行を読んで後で残りを読んでみたい。残念ながら、Pipes.Prelude.head関数が返った後。パイプは何とか閉じられています。最初にcsvの頭を読んで後で残りの部分を読む方法がありますか?我々は最初のヘッダを読んでいない場合はpcs-csvを使って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) 
       ) 

答えて

1

Pipes.Csvはヘッダを処理するための材料を持っているが、私はこの質問が本当に探していると思いますPipes.awaitまたはPipes.nextのより洗練された使用。まずnext

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

nextはプロデューサーを検査する基本的な方法です。これは、リスト上のパターンマッチングのようなものです。リストでは、[]x:xsの2つの可能性があります - ここでは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値がここに気晴らしされているので、私はLeft値なくす - P.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 

差がproducerが空の場合、私は」勝っただけのことです前のプログラムでNo lines!と同じようにこれを宣言することができます。 showPipeP.map showとして、または単にP.showとして定義することができ仕方によって

注意(しかし、あなたは追加の特殊なタイプで。)

+0

P.nextは、私の場合のための知事の溶液でした。また、showPipeのマップバージョンを表示していただきありがとうございます。 – yilmazhuseyin

+0

また、P.concatでEitherを削除するのは本当に素晴らしいトリックでした。 – yilmazhuseyin

関連する問題