简体   繁体   中英

Haskell type mismatch with csv parsing

I'm trying to parse a csv file where I want to ignore the first line and the last line, as in:

Someheader
foo, 1000,
bah, 2000,
somefooter

I wrote some Haskell using the cassava library:

{-# LANGUAGE OverloadedStrings #-}

import Control.Applicative
import qualified Data.ByteString.Lazy as BL
import Data.Csv
import qualified Data.Vector as V
import Control.Monad (mzero)

data Demand = Demand
    { name     :: !String
    , amount   :: !Int
    } deriving Show

instance FromRecord Demand where
    parseRecord r 
         | length == 2 = Demand <$> r .! 0
                                <*> r .! 1
         | otherwise = mzero

main :: IO ()
main = do
    csvData <- BL.readFile "demand.csv"
    case decode HasHeader csvData of
        Left err -> putStrLn err
        Right (_, v) -> V.forM_ v $ \ p ->
            putStrLn $ (name p) ++ " amount " ++ show (amount p)

When I run this get a type mismatch, that I can't figure out:

parser.hs:34:15: error:
    • Couldn't match expected type ‘V.Vector a2’
                  with actual type ‘(a1, V.Vector Demand)’
    • In the pattern: (_, v)
      In the pattern: Right (_, v)

My guess is that I haven't unpacked the Vector in the record correctly? Any help, gratefully received.

decode has the type FromRecord a => HasHeader -> ByteString-> Either String (Vector a) based on the documentation for cassava.
So the correct pattern would be Right v instead of Right (_, v) .

Another problem in the code, is that length is a function, and you didn't apply it to anything, in the guard | length == 2 = ... | length == 2 = ... . I believe the correct code should instead be | length r == 2 = ... | length r == 2 = ...

Here's the complete code after those changes:

{-# LANGUAGE OverloadedStrings #-}

import Control.Applicative
import qualified Data.ByteString.Lazy as BL
import Data.Csv
import qualified Data.Vector as V
import Control.Monad (mzero)

data Demand = Demand
    { name     :: !String
    , amount   :: !Int
    } deriving Show

instance FromRecord Demand where
    parseRecord r 
         | length r == 2 = Demand <$> r .! 0
                                <*> r .! 1
         | otherwise = mzero

main :: IO ()
main = do
    csvData <- BL.readFile "demand.csv"
    case decode HasHeader csvData of
        Left err -> putStrLn err
        Right v -> V.forM_ v $ \ p ->
            putStrLn $ (name p) ++ " amount " ++ show (amount p)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM