使用CSV管道将CSV文件解析为自定义数据类型

使用CSV管道将CSV文件解析为自定义数据类型,csv,haskell,conduit,Csv,Haskell,Conduit,我对如何将csv管道与自定义数据类型一起使用感到非常困惑。我想获取一行股票数据,例如: Date,Open,High,Low,Close,Volume,Adj Close 2017-02-10,2312.27002,2319.22998,2311.100098,2316.100098,3475020000,2316.100098 并将其解析为我在下面的MWE中声明的StockInfo类型。我从文档中收集了使我的StockInfo成为FromNamedRecord、ToNamedRecord和C

我对如何将csv管道与自定义数据类型一起使用感到非常困惑。我想获取一行股票数据,例如:

Date,Open,High,Low,Close,Volume,Adj Close
2017-02-10,2312.27002,2319.22998,2311.100098,2316.100098,3475020000,2316.100098
并将其解析为我在下面的MWE中声明的StockInfo类型。我从文档中收集了使我的StockInfo成为FromNamedRecord、ToNamedRecord和CSV ByteString实例所需的信息。我相信我已经在前两个版本中这样做了,但是我不知道如何通过TestRing实现CSV所需的方法。任何帮助都将不胜感激

MWE:


以下是我应该做的:

{-# LANGUAGE OverloadedStrings     #-}

module Lib
    ( readStocks
    ) where

import           Data.ByteString
import           Data.Conduit
import           Data.Conduit.Binary
import           Data.CSV.Conduit
import           Data.CSV.Conduit.Conversion
import           Data.Text                   (Text)
import           Data.Vector
import           System.IO

readStocks :: FilePath -> IO (Vector (Named StockInfo))
readStocks fp = readCSVFile defCSVSettings fp

data StockInfo = StockInfo
  { date     :: !String
  , open     :: !Double
  , high     :: !Double
  , low      :: !Double
  , close    :: !Double
  , volume   :: !Integer
  , adjClose :: !Double
  } deriving (Show, Eq, Read)

instance FromNamedRecord StockInfo where
  parseNamedRecord m =
    StockInfo <$>
    m .: "Date" <*>
    m .: "Open" <*>
    m .: "High" <*>
    m .: "Low" <*>
    m .: "Close" <*>
    m .: "Volume" <*>
    m .: "Adj Close"

instance ToNamedRecord StockInfo where
  toNamedRecord (StockInfo date open high low close volume adjClose) =
    namedRecord [ "Date" .= date
                , "Open" .= open
                , "High" .= high
                , "Low" .= low
                , "Close" .= close
                , "Volume" .= volume
                , "Adj Close" .= adjClose
                ]

以下是我应该做的:

{-# LANGUAGE OverloadedStrings     #-}

module Lib
    ( readStocks
    ) where

import           Data.ByteString
import           Data.Conduit
import           Data.Conduit.Binary
import           Data.CSV.Conduit
import           Data.CSV.Conduit.Conversion
import           Data.Text                   (Text)
import           Data.Vector
import           System.IO

readStocks :: FilePath -> IO (Vector (Named StockInfo))
readStocks fp = readCSVFile defCSVSettings fp

data StockInfo = StockInfo
  { date     :: !String
  , open     :: !Double
  , high     :: !Double
  , low      :: !Double
  , close    :: !Double
  , volume   :: !Integer
  , adjClose :: !Double
  } deriving (Show, Eq, Read)

instance FromNamedRecord StockInfo where
  parseNamedRecord m =
    StockInfo <$>
    m .: "Date" <*>
    m .: "Open" <*>
    m .: "High" <*>
    m .: "Low" <*>
    m .: "Close" <*>
    m .: "Volume" <*>
    m .: "Adj Close"

instance ToNamedRecord StockInfo where
  toNamedRecord (StockInfo date open high low close volume adjClose) =
    namedRecord [ "Date" .= date
                , "Open" .= open
                , "High" .= high
                , "Low" .= low
                , "Close" .= close
                , "Volume" .= volume
                , "Adj Close" .= adjClose
                ]

库已经定义了一个实例,从NamedRecord a到NamedRecord a,CSV s MapRow ByteString=>CSV s Named a-Named只是标识,并且您有{To/From}NamedRecord实例,所以您不需要自己编写这个实例-只需使用命名实例即可。如果你真的愿意,你可以根据库提供的通用实例,通过TestRing StockInfo实例来定义你的CSV。明白了!我认为这没有什么意义,但这是我对它的最好理解。库已经定义了一个实例,从NamedRecord a到NamedRecord a,CSV s MapRow ByteString=>CSV s Named a-Named只是标识,您有{To/From}NamedRecord实例,因此,您不需要自己编写这个实例,只需使用命名实例即可。如果你真的愿意,你可以根据库提供的通用实例,通过TestRing StockInfo实例来定义你的CSV。明白了!我认为这没有道理,但这是我最好的理解。