I have a CSV file containing some data about trains: stations from,
to,
times etc. and I wanted to 'learn some more Haskell' and, to my
astonishment,
I have gotten thus far but I am not sure *why* it works or *how* I
got
there! LMAO Here is the relevant code ...
====>
trains :: String -> IO ()
trains csvfile = do
legodata <- parseCSVFromFile csvfile
case legodata of
Left error -> print error
Right legodata -> mapM_ putStrLn (trainCodes legodata)
-- Assumes row 1 contains cell header information
-- Note: the train-code is always the third cell
trainCodes :: [Record] -> [String]
trainCodes = nub . map (!! 2) . tail
====>
I was chuffed with writing the trainCodes as a point-free function,
that sort of thing is getting a little easier to work with but I
still
have real head-banging frustrations sometimes with seemingly simple
things, like looping and just printing stuff out, despite having
taught myself
LISP six years ago and Erlang in recent years! I quit!! I really
do!!!
My confusion arises over: mapM_ putStrLn (traincodes legodata)
Given that: mapM_ :: Monad
m => (a -> m b) -> [a] -> m ()
Here's how I read it: For any m that is a Monad, mapM_ takes a
function that "takes
an 'a' and returns it wrapped in a monad", a "list of a's" and
returns a "monad containing
'unit'", the empty-list LISP-() undefined voidy thing.
Given that: putStrLn :: String
-> IO
(),
this means that 'a' is String and 'm b' is
IO () and my list of [a] is the result of calling 'traincodes
legodata'.
trainCodes = nub . map (!! 2) . tail
legodata is [Record] (from Text.CSV) and so, 'tail' removes the
header row from
the data, 'map (!! 2)' extracts the third field from each row and
finally 'nub'
removes the duplicates. Thus the return type from trainCodes is
[String].
Gluing it all together:
mapM_ :: Monad
m => (a -> m b) -> [a] -> m ()
putStrLn :: String
-> IO
()
trainCodes :: [Record] -> [String]
the type of my call then would seem to be:
String -> IO () -> [String] -> IO ()
"putStrLn" -> (trainCodes legodata) -> IO ()
which means that not only have I got the types correct for the call
but the result
type of 'IO ()' also satisfies the type return for my function and
hence it executes
from 'main' (where it is called from) with no issues.
So, am I finally beginning to get a grip on it all ? This list is a
constant source
of education and I don't post very often as you guys give me far too
much stuff to
be reading all the time! :)
I am using Text.CSV to read my file and all I wanted to do was to
output
a list of unique codes from column three of the spreadsheet data,
one per
line, so that I can use this Haskell as part of a bigger 'bash'
script.
Any detailed explanations that might help me better understand my
solution
would be welcome; right now I feel I 'just got lucky' although there
must
be a glimmer of understanding somewhere! LOL
Thanks,
Sean.
PS: Phew!