1

I'm able to parse my csv file using the following code from Data.Csv:

valuesToList :: Foo -> (Int, Int)
valuesToList (Foo a b) = (a,b)

loadMyData :: IO ()
loadMyData = do
  csvData <- BL.readFile "mydata.csv"
  case decodeByName csvData of
        Left err -> putStrLn err 
        Right (_, v) -> print $ V.toList $ V.map valuesToList v

When I run this I get the correct output on the screen. The problem I have is I'm not clear how to create a pure function so I can consume the contents of the list, as in:

let l = loadMyData

Where l is of type [Int,Int] I'm guessing it's because I'm in the IO Monad and I'm doing something hopelessly silly...

Anthony W
  • 1,289
  • 2
  • 15
  • 28

1 Answers1

3

I'm doing something hopelessly silly...

Yes, but worry not!

loadMyData = BL.readFile "mydata.csv"

processMyData :: String -> String
processMyData csvData = 
  case decodeByName csvData of
        Left err -> err 
        Right (_, v) -> show $ V.toList $ V.map valuesToList v

main = do
    csv <- loadMyData
    let output = processMyData csv
    print output

This way you separate the pure, "let" part from the impure loading part. This isn't Code Review (if you asked there, I could probably elaborate more), but I'd type the processing as String -> Either String [Int, Int] or something and keep the failure information in the type system.

processMyData csvData = 
  case decodeByName csvData of
        Left err -> Left err 
        Right (_, v) -> Right $ V.toList $ V.map valuesToList v

And that in turn could simply be (pardon me if I make a mistake somewhere, I'm doing it live):

processMyData = fmap (V.toList . V.map valuesToList) . decodeByName

That should work because of how the Functor instance for Either is constructed.


Oh, and also use Control.Applicative for bonus style points:

main = do
    output <- processMyData <$> loadMyData
    print output

(in case you don't understand that example, (<$>) is infix fmap, but that's not stricly necessary; hence bonus)

Community
  • 1
  • 1
Bartek Banachewicz
  • 38,596
  • 7
  • 91
  • 135
  • So now the compiler gives me this: Couldn't match type `BL.ByteString' with `[Char]' Expected type: String Actual type: BL.ByteString In the first argument of `processMyData', namely `csv' In the expression: processMyData csv In an equation for `output': output = processMyData csv – Anthony W Feb 02 '15 at 21:06
  • @AnthonyW I'm sorry for any mistakes I might have made. This should give you enough to get it to work, though – Bartek Banachewicz Feb 02 '15 at 21:07
  • 1
    yep. the type of signature of processMyData is ByteString -> String – Anthony W Feb 02 '15 at 21:17
  • and I'd like to get ByteString -> [(Int,Int)] – Anthony W Feb 02 '15 at 21:25
  • @AnthonyW [You might find this useful](https://www.haskell.org/hoogle/?hoogle=ByteString+-%3E+String). Sorry for not being there to help you yesterday, I had just enough time to write the answer. If you've managed (or manage to fix the problems in the future), edit my answer or add your own! – Bartek Banachewicz Feb 03 '15 at 09:01