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
In the declaration for
Personagainst name they have used!Stringinstead ofString, why? I ran the same example withStringand there was no difference in output. The tutorial on stack builders site also use the!. What am I missing here?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?
!before a type is called aBangPatternand 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 onvwhich is aVectorof rows, in your case of typePerson.V.forM_is a function of typeMonad m => Vector a -> (a -> m b) -> m ()from thevectorpackage. Essentially, it performs a monadic action for each element of the vector, in your case, anIOaction of typePerson -> IO (). Sopin this case, is an individualPerson.