Search code examples
csvhaskelliodecode

Haskell IO, cassava documentation, Data.csv


I am trying to learn IO in Haskell and I found it very confusing. Went through the cassava documentation on hackage under "use decodeByName:"

{-# LANGUAGE OverloadedStrings #-}

import Control.Applicative
import qualified Data.ByteString.Lazy as BL
import Data.Csv
import qualified Data.Vector as V

data Person = Person
    { name   :: !String
    , salary :: !Int
    }

instance FromNamedRecord Person where
    parseNamedRecord r = Person <$> r .: "name" <*> r .: "salary"

main :: IO ()
main = do
    csvData <- BL.readFile "salaries.csv"
    case decodeByName csvData of
        Left err -> putStrLn err
        Right (_, v) -> V.forM_ v $ \ p ->
            putStrLn $ name p ++ " earns " ++ show (salary p) ++ " dollars"

I have two questions here

  1. In the declaration for Person against name they have used !String instead of String, why? I ran the same example with String and there was no difference in output. The tutorial on stack builders site also use the !. What am I missing here?

  2. In the main function what does

            Right (_, v) -> V.forM_ v $ \ p ->
                putStrLn $ name p ++ " earns " ++ show (salary p) ++ " dollars"
    

    do?

I understand that post $ \ p is an anonymous function that puts a new string concatenating name from p and salary from p showing salary because it is an integer.

What does p stand for? Is it a tuple, a variable? Have they used p for the Person data structure?

What does the expression Right (_, v) -> V.forM_ v mean?


Solution

  • ! before a type is called a BangPattern and it causes the argument to be evaluated to weak head normal form when the data type is constructed. Informally, it decreases the amount of laziness which in some cases will improve performance.

    Right (_, v) -> V.forM_ v $ \p -> ... This part pattern matches on v which is a Vector of rows, in your case of type Person. V.forM_ is a function of type Monad m => Vector a -> (a -> m b) -> m () from the vector package. Essentially, it performs a monadic action for each element of the vector, in your case, an IO action of type Person -> IO (). So p in this case, is an individual Person.