In today’s Programming Praxis exercise, our task is to define functions to map, filter, fold and foreach over records in text file databases, for which we wrote parser’s in the previous exercise.
However, due to the way we wrote the functions last time, there really isn’t much point in doing so. Since the parsers already return a list of records (albeit wrapped in an Either and an IO), you can simply use the map, filter, foldl and mapM_ functions from the Prelude to process them. I suppose that in the Scheme solution it makes a little more sense, since there the parsers only return one record at a time, but even then I’d personally just write a function that returns all the records in a file and then process them like any other list, since it saves you from having to duplicate a lot of existing functions. Additionally, it makes function composition much easier, as the database-specific functions cannot be composed.
Of the four functions mentioned, the only one that warrants a function in Haskell is foreach (or in Haskell terminology, mapM_), since it requires doing something with the potential parse error:
dbMapM_ :: Monad m => (a -> m b) -> Either l [a] -> m () dbMapM_ = either (const $ return ()) . mapM_
The other three can just be fmapped over the result of readDB. I won’t bore you with the implementations for map, filter and foldl, since they would be largely identical to the ones found in the Prelude.
main :: IO () main = do db <- readDB (fixedLength [5,3,4]) "db_fl.txt" print $ map head <$> db print $ foldl (const . succ) 0 <$> db print $ filter (odd . length) <$> db dbMapM_ print db