Home > Mobile >  reading Csv as custom data types
reading Csv as custom data types

Time:12-14

I have a csv at some filePath with two columns with no headers

john,304
sarah,300
...

I have been able to read the csv as such:

import Data.Csv as Csv
import Data.ByteString.Lazy as BL
import Data.Vector as V

...
results <- fmap V.toList . Csv.decode @(String,Integer) Csv.NoHeader <$> BL.readFile filePath
-- Right [("john",300),("sarah",302)]

If I have custom data type for the csv columns as such:

data PersonnelData = PersonnelData
{ name :: !String
, amount :: !Integer
} deriving (Show, Generic, Csv.FromRecord)

How can I modify the above to decode / read the file for this data type?

CodePudding user response:

Where you have this:

Csv.decode @(String,Integer)

You are are using a visible type application to explicitly tell Csv.decode that its first type parameter should be the type (String, Integer). Let's have a look at the signature for decode to see what that means:

decode :: FromRecord a   
       => HasHeader 
       -> ByteString    
       -> Either String (Vector a)

There's only one type parameter, and it's pretty clear from where it appears (in the output) that it is the type that decode is decoding into. So Csv.decode @(String,Integer) is a function that explicitly decodes CSV records to (String, Integer).

So the only change you need to make to your code is to explicitly tell it you want to decode to PersonnelData instead of (String, Integer). Just use Csv.decode @PersonnelData. (You need a FromRecord instance, but you already have provided that by deriving it)

  • Related