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 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?
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 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
.