2017-02-13 2 views
1

analysieren Ich bin ziemlich verwirrt über die Verwendung von CSV-Conduit mit benutzerdefinierten Datentypen. Ich möchte eine Reihe von Bestandsdaten zu übernehmen, wie diese:CSV-Datei in benutzerdefinierter Datentyp mit CSV-Conduit

Date,Open,High,Low,Close,Volume,Adj Close 
2017-02-10,2312.27002,2319.22998,2311.100098,2316.100098,3475020000,2316.100098 

und analysieren, dass in den StockInfo Typ I unten in meinem MWE erklärt. Ich habe aus der Dokumentation, die ich brauche, um meine StockInfo eine Instanz von FromNamedRecord, ToNamedRecord und CSV ByteString gesammelt. Ich glaube, dass ich das für die ersten beiden getan habe, aber ich verstehe nicht, wie man die notwendigen Methoden für CSV ByteString implementiert. Jede Hilfe würde sehr geschätzt werden.

MWE:

{-# LANGUAGE MultiParamTypeClasses #-} 
{-# LANGUAGE OverloadedStrings  #-} 

module Lib 
    (readStocks 
    ) where 

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

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

data StockInfo = StockInfo 
    { date  :: !String 
    , open  :: !Double 
    , high  :: !Double 
    , low  :: !Double 
    , close :: !Double 
    , volume :: !Integer 
    , adjClose :: !Double 
    } 

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 
       ] 

instance CSV ByteString StockInfo where 
    -- rowToStr = undefined 
    -- intoCSV = undefined 
    -- fromCSV = undefined 
+1

Die Bibliothek bereits definiert eine Instanz '(FromNamedRecord a, ToNamedRecord a, CSV s (MapRow ByteString)) => CSV s (Benannt a) '-' Benannt 'ist nur die Identität, und Sie haben die '{To/From} NamedRecord'-Instanzen, so dass Sie diese Instanz nicht selbst schreiben müssen - benutzen Sie einfach die' Named' -Instanz. Wenn Sie wirklich wollen, können Sie Ihre 'CSV ByteString StockInfo'-Instanz in Bezug auf die allgemeine Bibliothek definieren, die von der Bibliothek bereitgestellt wird. – user2407038

+0

Verstanden! Ich fand das nicht sinnvoll, aber es war das beste Verständnis, das ich hatte. – anthonybrice

Antwort

2

Hier ist, was ich getan haben sollte:

{-# 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 
       ] 
Verwandte Themen