
On 10 Mar 2009, at 16:26, Roland Zumkeller wrote:
Hi Andy,
Here is a function that parses a comma-separated list of strings:
uncommas :: String -> [String] uncommas s = case break (==',') s of (w,[]) -> [w] (w,_:s') -> w : uncommas s'
We can then sum over the 4th column like this:
main = putStrLn . show . sum . map (read . (!!4) . uncommas) . tail . lines =<< getContents
This program is best read backwards: "getContents" gives stdin as a string and "lines" breaks it into lines. The (!!) function yields the nth element of a list. "read" and "show" convert between strings and integers.
An alternative solution, though similar is to implement a data type for each record, and implement read for it: data Gender = Male | Female data Ethnicity = European | Maori | .......... data Record = R {name :: String, gender :: Gender, age :: Int, ethnicity :: Ethnicity, books :: Int} instance Read Gender where readsPrec _ s = case toLower $ read s of {'m' -> [(Male,"")]; 'f' -
[(Female,"")]; _ -> []}
instance Read Ethnicity where ... instance Read Record where readsPrec _ = buildRec . uncommas where buildRec [n,g,a,e,b] = fromMaybe [] do (n',_) <- listToMaybe $ reads n (g',_) <- listToMaybe $ reads g (a',_) <- listToMaybe $ reads a (e',_) <- listToMaybe $ reads e (b',_) <- listToMaybe $ reads b return [(R n' g' a' e' b', "")] Now you can get at just the names for example by mapping the getter over the list: main = putStrLn . ("Names: " ++) . concat . intersperse " " . map (name . read) . lines =<< getContents Bob